- 1 R语言高效数据清理包dplyr学习
- 2 sep parameter
- 3 tab and new row
- 4 sep is a comma
- 5 skip & fill parameter
- 6 Load dplyr package
- 7 for a data.frame, is not nessary to change to tbl object
- 8 for sql object, can useful to use dplyr to manupulate data
- 9 another way to read data
- 10 filter a value that match some condition
- 11 filter value in 1 or 4
- 12 import data and change to tbl object
- 13 filter order data is 2009-10-13 rows
- 14 filter order data is 2009-10-13 rows and total price greater than 100 rows, 1 row match and assign to filterData
- 15 just select color column
- 16 select all other columns except color column equals select value column
- 17 e.g. order_tbl, check column
- 18 select order data and total price
- 19 rename column name at the same time
- 20 select starts with order column name
- 21 select contains id column name
- 22 rename function
- 23 after rename returns a new tbl, the origin Contains_ID will not be changed
- 24 e.g. with select from ? rename
- 25 Drop variables
- 26 Rename variables:
- 27 * select() keeps only the variables you specify
- 28 Reorder variables: keep the variable “Species” in the front
- 29 * rename() keeps all variables
- 30 Programming with select —————————————————
- 31 order use index
- 32 use arrange to order a data frame/tbl, default is aesc, 1 to 3
- 33 import data and change to tbl object
- 34 order by date
- 35 order by date & by price desc 3 to 1
- 36 add double column
- 37 add double column and quadruple column
- 38 use order data set to mutate year, month and date
- 39 import data and change to tbl object
- 40 mutate
- 41 transmute
- 42 Mutate adds new variables and preserves existing;
- 43 transmute drops existing variables.
- 44 multi parameter
- 45 use order data set to summarise
- 46 import data and change to tbl object
- 47 left_join like excel vlookup, all value in left table will remain, but not match value in right table will be set NA
- 48 inner_join, just remain left and right table match value,
- 49 and add column(right table data) in left table
- 50 and not match value in left table will be discarded
- 51 semi_join, just remain left table that matches the value in right table, and right table value will not used
- 52 anti_join, just convert with semi_join, just keep match values in right table
- 53 use order and custimer data set to join
- 54 import data and change to tbl object
- 55 group by color
- 56 use order data set
- 57 import data and change to tbl object
- 58 mutate year and month column
- 59 group by year
- 60 summary yearly price and average price, and max month for check data period(year 2014 just have 5 month)
- 61 summarise support multi parameter
- 62 use order data set
- 63 01. import data and change to tbl object
- 64 03. mutate year and month column
- 65 04. group by month
- 66 05. summarise order count by month
- 67 use pipe function rewrite above flow 03,04,05
- 68 import data
- 69 Get Yearly Order data and split by year
- 70 Group by Year, Get Yealy Maximun Order
- 71 import data
- 72 Get Yearly Order data and split by year
- 73 Group by Year, Get Yealy Max 2 Orders
- 74 load and check iris data set
- 75 to round every column use colwise function
- 76 call function to each column
- 77 colwise(function)(data.frame)
- 78 mysql table
- 79 execute sql command
- 80 check sql query command
- 81 save results as csv file
- 82 show sqlQueryResults
- 83 mysql data base
- 84 mysql -u root -p
- 85 enter password
- 86 show databases
- 87 show databases
- 88 use which database, change to your database
- 89 use mydatabase
- 90 show tables in your database
- 91 show tables
R语言高效数据清理包dplyr学习
xueqin.tv
Chapter0 dplyr介绍
dplyr是一款用于数据整理的R包,本节内容介绍了dplyr的特性以及雪晴数据网《dplyr高效数据清理》的基本的内容,感兴趣的同学请尽快报名 {r Load dplyr package} # Load dplyr package if(!suppressWarnings(require(dplyr))) { install.packages('dplyr') require(dplyr) }
Chapter1 数据导入
介绍如何将文本格式的数据导入到R的内存,主要介绍read.table和read.csv函数,及常用参数的使用
read.table
read.table( ## file path file, ## 1st line as header/column name header = FALSE, ## separator strings sep = “”, ## how manhy rows need read nrows = -1, ## how manuy rows need skip skip = 0, ## not available data define as NA fill = !blank.lines.skip)
```{r read.table instruction} #example read.table(file = “dplyr-data/read.table/file1.txt”) # V1 V2 V3 # 1 name age height # 2 John 10 150 # 3 Jack 27 180 # 4 Mary 29 167
read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167
file1.data <- read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE) file1.data
sep parameter
read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE, sep = " “) # name.age.height # 1 John10150 # 2 Jack27180 # 3 Mary29167
tab and new row
cat(“1”) # 1 cat(“1”) # # # 1
read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE, sep = “”) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167
sep is a comma
read.table(file = “dplyr-data/read.table/file2.txt”, header = TRUE, sep = “,”) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167
skip & fill parameter
read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE) # Error in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : # line 4 did not have 3 elements
read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE, nrows = 4) # Error in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : # line 4 did not have 3 elements
read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE, nrows = 3) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167 # but we missing 1 row, so skip parameter is used as follow
read.table(file = “dplyr-data/read.table/file3.txt”, header = FALSE, skip = 5) # V1 V2 V3 # 1 Steven 45 175 # skip 1st 5 rows and no header
read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE, fill = T) # fill missing values as NA # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167 # 4 DDD NA NA # 5 Steven 45 175
```
read.csv
{r import order data by read.csv} # import data and change to tbl object order <- read.csv("dplyr-data/order.csv") head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5)
Chapter2 tbl对象的介绍
本节内容介绍如果用data.frame对象构造成tbl对象 tbl是dplyr定义的数据类型,可以接受data.frame,cube,sql ```{r import data by read.table} # import data order <- read.table(file = “dplyr-data/order.csv”, header = T, sep = “,”) class(order) # [1] “data.frame” head(order) tail(order)
Load dplyr package
if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) } # change to tbl use tbl_df function order_tbl <- tbl_df(order) class(order_tbl) # [1] “tbl_df” “tbl” “data.frame” order_tbl
for a data.frame, is not nessary to change to tbl object
for sql object, can useful to use dplyr to manupulate data
another way to read data
library(readr) order <- read_csv(“E:/03-Download/dplyr/dplyr-data/order.csv”) View(order) ```
Chapter3 数据筛选–filter函数
filter(tbl/data.fram, condition) and output a data.frame, filter rows/observation ```{r filter in dplyr} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }
df <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df) tbl # # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5
filter a value that match some condition
filter(tbl, color == “blue”) # # A tibble: 3 × 2 # color value # # 1 blue 1 # 2 blue 3 # 3 blue 4
filter value in 1 or 4
filter(tbl, value %in% c(1,4)) # A tibble: 2 × 2 # color value # # 1 blue 1 # 2 blue 4
import data and change to tbl object
order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5)
filter order data is 2009-10-13 rows
filter(order_tbl, orderdate == “2009-10-13”)
filter order data is 2009-10-13 rows and total price greater than 100 rows, 1 row match and assign to filterData
filterData <- filter(order_tbl, orderdate == “2009-10-13” & totalprice > 100) View(filterData) ```
Chapter4 子集选取函数–select
select columns/variable by name/match rules ```{r select function in dplyr} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }
df <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df) tbl
just select color column
select(tbl, color) # A tibble: 5 × 1 # color # # 1 blue # 2 black # 3 blue # 4 blue # 5 black
select all other columns except color column equals select value column
select(tbl, -color) # A tibble: 5 × 1 # value # # 1 1 # 2 2 # 3 3 # 4 4 # 5 5 ```
Useful function to select ```{r Useful function to select} starts_with(x, ignore.case = TRUE) # column/variable start with chart x ends_with(x, ignore.case = TRUE) # column/variable end with chart x contains(x, ignore.case = TRUE) # column/variable contains chart x matches(x, ignore.case = TRUE) # column/variable matches regular expression x num_range(“x”, 1:5, width = 2) # column/variable from x01 to x05 one_of(“x”, “y”, “z”) # column/variable contains in x, y, z everything() # all column/variable
e.g. order_tbl, check column
names(order_tbl) # [1] “X” “orderid” “customerid” “campaignid” # [5] “orderdate” “city” “state” “zipcode” # [9] “paymenttype” “totalprice” “numorderlines” “numunits”
select order data and total price
date_price <- select(order_tbl,orderdate, totalprice) date_price
rename column name at the same time
date_price2 <- select(order_tbl,date = orderdate, price = totalprice) date_price2
select starts with order column name
Start_With_Order <- select(order_tbl,starts_with(“order”,ignore.case = TRUE)) Start_With_Order # A tibble: 100,000 × 2 # orderid orderdate # # 1 1002854 2009-10-13 # 2 1002855 2009-10-13 # 3 1002856 2011-06-02 # 4 1002857 2009-10-14 # 5 1002886 2010-11-19 # 6 1002887 2009-10-15 # 7 1002888 2009-10-15 # 8 1002889 2009-10-15 # 9 1002890 2009-10-15 # 10 1003004 2009-10-15 # … with 99,990 more rows
select contains id column name
Contains_ID <- select(order_tbl, contains(“id”,ignore.case = TRUE)) head(Contains_ID,5) # A tibble: 5 × 3 # orderid customerid campaignid # # 1 1002854 45978 2141 # 2 1002855 125381 2173 # 3 1002856 103122 2141 # 4 1002857 130980 2173 # 5 1002886 48553 2141
rename function
as.data.frame(Contains_ID) # rename the new name must at the left after_rename <- rename(Contains_ID, ooID = orderid, ooID = customerid, ooCAID = campaignid) head(Contains_ID,5) # A tibble: 5 × 3 # orderid customerid campaignid # # 1 1002854 45978 2141 # 2 1002855 125381 2173 # 3 1002856 103122 2141 # 4 1002857 130980 2173 # 5 1002886 48553 2141
after rename returns a new tbl, the origin Contains_ID will not be changed
head(after_rename,5) # A tibble: 5 × 3 # ooID ooID ooCAID # # 1 1002854 45978 2141 # 2 1002855 125381 2173 # 3 1002856 103122 2141 # 4 1002857 130980 2173 # 5 1002886 48553 2141 # this works in the code below head(rename(iris, pt = Petal.Length),5)
e.g. with select from ? rename
iris <- tbl_df(iris) # so it prints a little nicer select(iris, starts_with(“Petal”)) select(iris, ends_with(“Width”)) select(iris, contains(“etal”)) select(iris, matches(“.t.”)) select(iris, Petal.Length, Petal.Width) vars <- c(“Petal.Length”, “Petal.Width”) select(iris, one_of(vars))
df <- as.data.frame(matrix(runif(100), nrow = 10)) df <- tbl_df(df[c(3, 4, 7, 1, 9, 8, 5, 2, 6, 10)]) select(df, V4:V6) select(df, num_range(“V”, 4:6))
Drop variables
select(iris, -starts_with(“Petal”)) select(iris, -ends_with(“Width”)) select(iris, -contains(“etal”)) select(iris, -matches(“.t.”)) select(iris, -Petal.Length, -Petal.Width)
Rename variables:
* select() keeps only the variables you specify
select(iris, petal_length = Petal.Length) # Renaming multiple variables uses a prefix: select(iris, petal = starts_with(“Petal”))
Reorder variables: keep the variable “Species” in the front
select(iris, Species, everything())
* rename() keeps all variables
rename(iris, petal_length = Petal.Length)
Programming with select —————————————————
select_(iris, ~Petal.Length) select_(iris, “Petal.Length”) select_(iris, lazyeval::interp(~matches(x), x = “.t.”)) select_(iris, quote(-Petal.Length), quote(-Petal.Width)) select_(iris, .dots = list(quote(-Petal.Length), quote(-Petal.Width))) ```
Chapter5 数据的排序–arrange函数
traditional method: order function ```{r use order to order} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }
df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df1) tbl # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5
order use index
df_order <- order(df1$color) df_order # [1] 2 5 1 3 4 df1[df_order,] # color value # 2 black 2 # 5 black 5 # 1 blue 1 # 3 blue 3 # 4 blue 4
use arrange to order a data frame/tbl, default is aesc, 1 to 3
arrange(df1, color) # use desc to order by 3 to 1 arrange(df1, desc(color))
import data and change to tbl object
order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5)
order by date
tbl <- select(order_tbl, odate = orderdate, oprice = totalprice) arrange(tbl, odate) # A tibble: 100,000 × 2 # odate oprice # # 1 2009-10-04 200 # 2 2009-10-04 120 # 3 2009-10-04 100 # 4 2009-10-04 100 # 5 2009-10-04 70 # 6 2009-10-04 50 # 7 2009-10-04 50 # 8 2009-10-04 40 # 9 2009-10-04 40 # 10 2009-10-04 40 # … with 99,990 more rows
order by date & by price desc 3 to 1
arrange(tbl, odate, desc(oprice)) # A tibble: 100,000 × 2 # odate oprice # # 1 2009-10-04 200 # 2 2009-10-04 120 # 3 2009-10-04 100 # 4 2009-10-04 100 # 5 2009-10-04 70 # 6 2009-10-04 50 # 7 2009-10-04 50 # 8 2009-10-04 40 # 9 2009-10-04 40 # 10 2009-10-04 40 # … with 99,990 more rows ```
Chapter6 数据扩展–mutate函数
数据扩展,保留原来的变量、列的基础上增加变量或者列 ```{r mutate function} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }
df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df1) tbl # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5
add double column
mutate(tbl, double = 2 * value) # A tibble: 5 × 3 # color value double # # 1 blue 1 2 # 2 black 2 4 # 3 blue 3 6 # 4 blue 4 8 # 5 black 5 10
add double column and quadruple column
mutate(tbl, double = 2 * value, quadruple = 4 * value) # A tibble: 5 × 4 # color value double quadruple # # 1 blue 1 2 4 # 2 black 2 4 8 # 3 blue 3 6 12 # 4 blue 4 8 16 # 5 black 5 10 20
use order data set to mutate year, month and date
import data and change to tbl object
order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5) tbl <- select(order_tbl, odate = orderdate, oprice = totalprice) tbl <- arrange(tbl, odate, desc(oprice)) head(tbl, 5) # # A tibble: 5 × 2 # odate oprice # # 1 2009-10-04 200 # 2 2009-10-04 120 # 3 2009-10-04 100 # 4 2009-10-04 100 # 5 2009-10-04 70
mutate
tbl_New <- mutate(tbl, oYear = substr(odate, 1, 4), oMonth = substr(odate, 6, 7),oDate = substr(odate, 9, 10)) head(tbl_New,5) # A tibble: 5 × 5 # odate oprice oYear oMonth oDate # # 1 2009-10-04 200 2009 10 04 # 2 2009-10-04 120 2009 10 04 # 3 2009-10-04 100 2009 10 04 # 4 2009-10-04 100 2009 10 04 # 5 2009-10-04 70 2009 10 04
transmute
Mutate adds new variables and preserves existing;
transmute drops existing variables.
df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl_transmute <- tbl_df(df1) tbl_transmute # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5
transmute(tbl_transmute, double = 2 * value, quadruple = 4 * value) # A tibble: 5 × 2 # double quadruple # # 1 2 4 # 2 4 8 # 3 6 12 # 4 8 16 # 5 10 20 ```
Chapter7 数据汇总–summarise函数
数据汇总-将多个值汇总为一个数据值 ```{r summarise} df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl_summarise <- tbl_df(df1)
summarise(tbl_summarise, total = sum(value)) # A tibble: 1 × 1 # total # # 1 15
multi parameter
summarise(tbl_summarise, total_value = sum(value), mean_value = mean(value), sd_value = sd(value)) # A tibble: 1 × 3 # total_value mean_value sd_value # # 1 15 3 1.581139
use order data set to summarise
import data and change to tbl object
order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5) tbl <- select(order_tbl, odate = orderdate, oprice = totalprice) # tbl <- arrange(tbl, odate, desc(oprice)) summarise(tbl, max = max(oprice), min = min(oprice), mean = mean(oprice)) # A tibble: 1 × 3 # max min mean # # 1 6780 0 60.77773
``` summarise()中的汇总函数将一列值转换为一个单独的值输出 R自带的统计函数都是可以使用的 min(), max(), mean(), sum(), sd(), median(), IQR()
此外,dplyr还提供了一些其他会用到的函数 n():观测值的个数 n_distinct(x):不相同的观测值的个数 first(x),last(x)和nth(x, n)获取第一个,最后一个,和第n个数据
{r first and last value} summarise(tbl, first = first(odate), last = last(odate)) # A tibble: 1 × 2 # first last # <fctr> <fctr> # 1 2009-10-13 2014-04-28
Chapter8 数据连接–join函数
dplyr advanced function: - data set join/connection, like excel vlookup function - group_by - pipe function: %>% - other function: do, plyr::colwise - mysql database connection
```{r join} x <- data.frame(name = c(“John”, “Paul”, “George”, “Ringo”, “Stuart”, “Siqin”), instrument = c(“guitar”, “bass”, “guitar”, “drums”, “bass”, “drums”)) x # name instrument # 1 John guitar # 2 Paul bass # 3 George guitar # 4 Ringo drums # 5 Stuart bass # 6 Siqin drums y <- data.frame(name = c(“John”, “Paul”, “George”, “Ringo”, “Brian”), band = c(T, T, T, T, T)) y # name band # 1 John TRUE # 2 Paul TRUE # 3 George TRUE # 4 Ringo TRUE # 5 Brian TRUE
left_join like excel vlookup, all value in left table will remain, but not match value in right table will be set NA
left_join(x, y, by = “name”) # name instrument band # 1 John guitar TRUE # 2 Paul bass TRUE # 3 George guitar TRUE # 4 Ringo drums TRUE # 5 Stuart bass NA # 6 Siqin drums NA
inner_join, just remain left and right table match value,
and add column(right table data) in left table
and not match value in left table will be discarded
inner_join(x, y, by = “name”) # name instrument band # 1 John guitar TRUE # 2 Paul bass TRUE # 3 George guitar TRUE # 4 Ringo drums TRUE
semi_join, just remain left table that matches the value in right table, and right table value will not used
semi_join(x, y, by = “name”) # name instrument # 1 John guitar # 2 Paul bass # 3 George guitar # 4 Ringo drums
anti_join, just convert with semi_join, just keep match values in right table
anti_join(x, y, by = “name”) # name instrument # 1 Siqin drums # 2 Stuart bass
use order and custimer data set to join
import data and change to tbl object
df_order <- read.csv(“dplyr-data/order.csv”) df_customer <- read.csv(“dplyr-data/customer.csv”) head(df_order,5) head(df_customer,5)
tbl_order <- tbl_df(df_order) tbl_customer <- tbl_df(df_customer)
s_order <- select(tbl_order, odate = orderdate, ocust_id = customerid) s_customer <- select(tbl_customer, ocust_id = customerid, gender, firstname,lastname =Lastname)
arrange(left_join(s_order, s_customer, by = “ocust_id”), firstname) ```
Chapter9 分类汇总 – group_by
分类汇总 – group_by ```{r group_by function} #summary by year–Group-wise summary # group_by()转变成一 个分好组的数据框
df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) summarise(df1, total =sum(value)) # just get one sumarised data total # total # 1 15
group by color
by_color <- group_by(df1, color) # then summarise by group summarise(by_color, total = sum(value)) # A tibble: 2 × 2 # color total # # 1 black 7 # 2 blue 8
use order data set
import data and change to tbl object
df_order <- read.csv(“dplyr-data/order.csv”) head(df_order,5)
tbl_order <- tbl_df(df_order) # tbl_customer <- tbl_df(df_customer)
s_order <- select(tbl_order, odate = orderdate, oprice = totalprice)
mutate year and month column
m_order <- mutate(s_order, oyear = substr(odate, 1, 4), omonth = substr(odate, 6, 7)) head(m_order, 5)
group by year
m_order_year <- group_by(m_order, oyear) head(m_order_year) # Source: local data frame [6 x 4] # Groups: oyear [3] # # odate oprice oyear omonth # # 1 2009-10-13 190.00 2009 10 # 2 2009-10-13 10.00 2009 10 # 3 2011-06-02 35.22 2011 06 # 4 2009-10-14 10.00 2009 10 # 5 2010-11-19 10.00 2010 11 # 6 2009-10-15 10.00 2009 10
summary yearly price and average price, and max month for check data period(year 2014 just have 5 month)
summarise support multi parameter
summarise(m_order_year, yearly_price = sum(oprice), average_price = mean(oprice), Max_Month = max(omonth)) # A tibble: 6 × 4 # oyear yearly_price average_price max(omonth)
# # 1 2009 262627.5 34.13850 12 # 2 2010 967429.2 52.23982 12 # 3 2011 1380636.6 51.35342 12 # 4 2012 1404113.1 68.40990 12 # 5 2013 1633004.8 76.71011 12 # 6 2014 429962.0 84.47190 05 ```
Chapter10 管道函数
%>% or %.% use the previous function(left)’s out put as the next function(right)’s input. ```{r pipe function} 1:5 %>% mean() # [1] 3 1:5 %>% mean(.) %>% sqrt() # [1] 1.732051
use order data set
01. import data and change to tbl object
df_order <- read.csv(“dplyr-data/order.csv”) head(df_order,5) # 02. change to tbl object tbl_order <- tbl_df(df_order) head(tbl_order, 5)
03. mutate year and month column
m_order <- mutate(tbl_order, oyear = substr(orderdate, 1, 4), omonth = substr(orderdate, 6, 7)) head(m_order, 5)
04. group by month
m_order_month <- group_by(m_order,omonth)
05. summarise order count by month
summarise(m_order_month, monthly_order_count = n())
use pipe function rewrite above flow 03,04,05
tbl_order %>% mutate(oyear = substr(orderdate, 1, 4), omonth = substr(orderdate, 6, 7)) %>% group_by(omonth) %>% summarise(monthly_order_count = n()) # A tibble: 12 × 2 # omonth monthly_order_count # # 1 01 13601 # 2 02 6609 # 3 03 6235 # 4 04 6042 # 5 05 5037 # 6 06 4691 # 7 07 4354 # 8 08 4763 # 9 09 5676 # 10 10 7106 # 11 11 17268 # 12 12 18618
```
Chapter11 colwise和do函数
筛选销售额每年最大的记录 ```{r colwise and do function} # Load dplyr package if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }
import data
order <- read.csv(“dplyr-data/order.csv”)
Get Yearly Order data and split by year
Yearly_Order <- order %>% select(orderdate, totalprice) %>% mutate(oyear = substr(orderdate, 1, 4))
Group by Year, Get Yealy Maximun Order
Yealy_Maximun <- Yearly_Order %>% group_by(oyear) %>% summarise(max(totalprice))
```
筛选每年销售额最大的两条记录 ```{r do(data, fun(.))} # Load dplyr package if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }
import data
order <- read.csv(“dplyr-data/order.csv”)
Get Yearly Order data and split by year
Yearly_Order <- order %>% select(orderdate, totalprice) %>% mutate(oyear = substr(orderdate, 1, 4))
Group by Year, Get Yealy Max 2 Orders
Yearly_Order %>% group_by(oyear) %>% arrange(desc(totalprice)) %>% do(., head(., 2)) # Source: local data frame [12 x 3] # Groups: oyear [6] # # orderdate totalprice oyear # # 1 2009-12-17 2244.00 2009 # 2 2009-10-26 1154.65 2009 # 3 2010-09-05 2250.00 2010 # 4 2010-10-06 2250.00 2010 # 5 2011-05-09 2250.00 2011 # 6 2011-05-17 2000.00 2011 # 7 2012-12-12 6780.00 2012 # 8 2012-11-12 6606.00 2012 # 9 2013-01-18 4050.00 2013 # 10 2013-06-26 3592.00 2013 # 11 2014-03-29 4735.00 2014 # 12 2014-03-30 4378.50 2014
```
plyr package colwise function
```{r colwise function} # Load plyr package if(!suppressWarnings(require(plyr))) { install.packages(‘plyr’) require(plyr) }
load and check iris data set
head(iris, 5)
to round every column use colwise function
call function to each column
colwise(function)(data.frame)
colwise(round)(iris[, 1:4]) %>% head(., 5) # Sepal.Length Sepal.Width Petal.Length Petal.Width # 1 5 4 1 0 # 2 5 3 1 0 # 3 5 3 1 0 # 4 5 3 2 0 # 5 5 4 1 0
```
Chapter12 连接MySQL数据库
连接MySQL数据库 ```{r connect mysql} # mysql data base src_database <- src_mysql(dbname = “sqlbook”, host = “127.0.0.1”, port = “3063”,user = “root”,password = “root”)
mysql table
src_table <- tbl(src_database, from = “orders”)
execute sql command
sqlQueryResults <- select(src_table, orderid, orderdate) # or use pipe function sqlQueryResults <- src_table %>% select(orderid, orderdate)
check sql query command
sqlQueryResults$query
save results as csv file
write.csv(sqlQueryResults, “dplyr-data/order_record.csv”)
show sqlQueryResults
sqlQueryResults
mysql data base
mysql -u root -p
enter password
show databases
show databases
use which database, change to your database
use mydatabase
show tables in your database
show tables
```
Chapter13 Example dplyr and pipeline operator
dplyr Examples with pipeline
rlist Examples with pipeline
hflights
is a dataset contains information about flights that departed Houston in 2011. In the description the author writes:
This dataset contains all flights departing from Houston airports IAH (George Bush Intercontinental) and HOU (Houston Hobby). The data comes from the Research and Innovation Technology Administration at the Bureau of Transporation statistics: http://www.transtats.bts.gov/DatabaseInfo.asp?DB_ID=120&Link=0
Having known what the data is all about, then we load the libraries and take a look at the structure of the data.
install.packages(c("dplyr","hflights"))
library(dplyr)
library(pipeR)
# or use
library(magrittr)
library(hflights) # install.packages("hflights")
data(hflights)
str(hflights)
# 'data.frame': 227496 obs. of 21 variables:
# $ Year : int 2011 2011 2011 2011 2011 2011 2011 2011 2011 2011 ...
# $ Month : int 1 1 1 1 1 1 1 1 1 1 ...
# $ DayofMonth : int 1 2 3 4 5 6 7 8 9 10 ...
# $ DayOfWeek : int 6 7 1 2 3 4 5 6 7 1 ...
# $ DepTime : int 1400 1401 1352 1403 1405 1359 1359 1355 1443 1443 ...
# $ ArrTime : int 1500 1501 1502 1513 1507 1503 1509 1454 1554 1553 ...
# $ UniqueCarrier : chr "AA" "AA" "AA" "AA" ...
# $ FlightNum : int 428 428 428 428 428 428 428 428 428 428 ...
# $ TailNum : chr "N576AA" "N557AA" "N541AA" "N403AA" ...
# $ ActualElapsedTime: int 60 60 70 70 62 64 70 59 71 70 ...
# $ AirTime : int 40 45 48 39 44 45 43 40 41 45 ...
# $ ArrDelay : int -10 -9 -8 3 -3 -7 -1 -16 44 43 ...
# $ DepDelay : int 0 1 -8 3 5 -1 -1 -5 43 43 ...
# $ Origin : chr "IAH" "IAH" "IAH" "IAH" ...
# $ Dest : chr "DFW" "DFW" "DFW" "DFW" ...
# $ Distance : int 224 224 224 224 224 224 224 224 224 224 ...
# $ TaxiIn : int 7 6 5 9 9 6 12 7 8 6 ...
# $ TaxiOut : int 13 9 17 22 9 13 15 12 22 19 ...
# $ Cancelled : int 0 0 0 0 0 0 0 0 0 0 ...
# $ CancellationCode : chr "" "" "" "" ...
# $ Diverted : int 0 0 0 0 0 0 0 0 0 0 ...
The data is tabular and very well fit in a data frame. Remarkably it has 227496 rows which is much larger than small datasets like mtcars.
Two columns in the data frame attracts our attention: Distance
and ActualElapsedTime
. If we divide Distance by ActualElapsedTime we can get the actual flight speed. Therefore, in this example, we use dplyr functions to transform the data in pipeline and see which carrier has faster flights.
hflights %>%
# 1. filter out no canceld flight
filter(Cancelled == 0) %>%
# 2. mutate new column speed
mutate(speed = Distance / ActualElapsedTime) %>%
# 3. save to hflights2
(~ hflights2) %>%
# 4. group_by UniqueCarrier
group_by(UniqueCarrier) %>%
#group_by(.data = .,UniqueCarrier) %>%
# 5. summarize
summarize(mean_speed = mean(speed,na.rm = TRUE)) %>%
# 6. arrange, by speed desc
arrange(desc(mean_speed)) %>%
# 7. barplot, why with?
with(barplot(mean_speed,names.arg = UniqueCarrier,
main = "Average flight speed"))
End 2017-06-10 By Stone.Hou
Updated in 20170702, add example
LS0tDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KLS0tDQoNCiMgUuivreiogOmrmOaViOaVsOaNrua4heeQhuWMhWRwbHly5a2m5LmgDQo+IFt4dWVxaW4udHZdKGh0dHA6Ly93d3cueHVlcWluZy50di9sZXNzb24vODMpDQoNCiMjIENoYXB0ZXIwIGRwbHly5LuL57uNDQpkcGx5cuaYr+S4gOasvueUqOS6juaVsOaNruaVtOeQhueahFLljIXvvIzmnKzoioLlhoXlrrnku4vnu43kuoZkcGx5cueahOeJueaAp+S7peWPiumbquaZtOaVsOaNrue9keOAimRwbHly6auY5pWI5pWw5o2u5riF55CG44CL55qE5Z+65pys55qE5YaF5a6577yM5oSf5YW06Laj55qE5ZCM5a2m6K+35bC95b+r5oql5ZCNDQpgYGB7ciBMb2FkIGRwbHlyIHBhY2thZ2V9DQojIExvYWQgZHBseXIgcGFja2FnZQ0KaWYoIXN1cHByZXNzV2FybmluZ3MocmVxdWlyZShkcGx5cikpKQ0Kew0KICAgIGluc3RhbGwucGFja2FnZXMoJ2RwbHlyJykNCiAgICByZXF1aXJlKGRwbHlyKQ0KfQ0KYGBgDQoNCg0KIyMgQ2hhcHRlcjEg5pWw5o2u5a+85YWlDQrku4vnu43lpoLkvZXlsIbmlofmnKzmoLzlvI/nmoTmlbDmja7lr7zlhaXliLBS55qE5YaF5a2Y77yM5Li76KaB5LuL57uNcmVhZC50YWJsZeWSjHJlYWQuY3N25Ye95pWw77yM5Y+K5bi455So5Y+C5pWw55qE5L2/55SoDQoNCiMjIyByZWFkLnRhYmxlDQoNCnJlYWQudGFibGUoDQogICAgIyMgZmlsZSBwYXRoDQogICAgZmlsZSwNCiAgICAjIyAxc3QgbGluZSBhcyBoZWFkZXIvY29sdW1uIG5hbWUNCiAgICBoZWFkZXIgPSBGQUxTRSwNCiAgICAjIyBzZXBhcmF0b3Igc3RyaW5ncw0KICAgIHNlcCA9ICIiLA0KICAgICMjIGhvdyBtYW5oeSByb3dzIG5lZWQgcmVhZA0KICAgIG5yb3dzID0gLTEsDQogICAgIyMgaG93IG1hbnV5IHJvd3MgbmVlZCBza2lwDQogICAgc2tpcCA9IDAsDQogICAgIyMgbm90IGF2YWlsYWJsZSBkYXRhIGRlZmluZSBhcyBOQQ0KICAgIGZpbGwgPSAhYmxhbmsubGluZXMuc2tpcCkNCg0KYGBge3IgcmVhZC50YWJsZSBpbnN0cnVjdGlvbn0NCiNleGFtcGxlDQpyZWFkLnRhYmxlKGZpbGUgPSAiZHBseXItZGF0YS9yZWFkLnRhYmxlL2ZpbGUxLnR4dCIpDQojICAgICBWMSAgVjIgICAgIFYzDQojIDEgbmFtZSBhZ2UgaGVpZ2h0DQojIDIgSm9obiAgMTAgICAgMTUwDQojIDMgSmFjayAgMjcgICAgMTgwDQojIDQgTWFyeSAgMjkgICAgMTY3DQoNCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFKQ0KIyAgIG5hbWUgYWdlIGhlaWdodA0KIyAxIEpvaG4gIDEwICAgIDE1MA0KIyAyIEphY2sgIDI3ICAgIDE4MA0KIyAzIE1hcnkgIDI5ICAgIDE2Nw0KDQpmaWxlMS5kYXRhIDwtIHJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFKQ0KZmlsZTEuZGF0YQ0KDQojIHNlcCBwYXJhbWV0ZXINCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHNlcCA9ICIgIikNCiMgICBuYW1lLmFnZS5oZWlnaHQNCiMgMSAgIEpvaG5cdDEwXHQxNTANCiMgMiAgIEphY2tcdDI3XHQxODANCiMgMyAgIE1hcnlcdDI5XHQxNjcNCg0KIyB0YWIgYW5kIG5ldyByb3cNCmNhdCgiXHRcdFx0MSIpDQoJCQkjIDENCmNhdCgiXG5cblx0MSIpDQojDQojDQojIAkxDQoNCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHNlcCA9ICJcdCIpDQojICAgbmFtZSBhZ2UgaGVpZ2h0DQojIDEgSm9obiAgMTAgICAgMTUwDQojIDIgSmFjayAgMjcgICAgMTgwDQojIDMgTWFyeSAgMjkgICAgMTY3DQoNCiMgc2VwIGlzIGEgY29tbWENCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTIudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHNlcCA9ICIsIikNCiMgICBuYW1lIGFnZSBoZWlnaHQNCiMgMSBKb2huICAxMCAgICAxNTANCiMgMiBKYWNrICAyNyAgICAxODANCiMgMyBNYXJ5ICAyOSAgICAxNjcNCg0KIyBza2lwICYgZmlsbCBwYXJhbWV0ZXINCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTMudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFKQ0KIyBFcnJvciBpbiBzY2FuKGZpbGUgPSBmaWxlLCB3aGF0ID0gd2hhdCwgc2VwID0gc2VwLCBxdW90ZSA9IHF1b3RlLCBkZWMgPSBkZWMsICA6DQojICAgbGluZSA0IGRpZCBub3QgaGF2ZSAzIGVsZW1lbnRzDQoNCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTMudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIG5yb3dzID0gNCkNCiMgRXJyb3IgaW4gc2NhbihmaWxlID0gZmlsZSwgd2hhdCA9IHdoYXQsIHNlcCA9IHNlcCwgcXVvdGUgPSBxdW90ZSwgZGVjID0gZGVjLCAgOg0KIyAgIGxpbmUgNCBkaWQgbm90IGhhdmUgMyBlbGVtZW50cw0KDQpyZWFkLnRhYmxlKGZpbGUgPSAiZHBseXItZGF0YS9yZWFkLnRhYmxlL2ZpbGUzLnR4dCIsDQogICAgaGVhZGVyID0gVFJVRSwNCiAgICBucm93cyA9IDMpDQojICAgbmFtZSBhZ2UgaGVpZ2h0DQojIDEgSm9obiAgMTAgICAgMTUwDQojIDIgSmFjayAgMjcgICAgMTgwDQojIDMgTWFyeSAgMjkgICAgMTY3DQojIGJ1dCB3ZSBtaXNzaW5nIDEgcm93LCBzbyBza2lwIHBhcmFtZXRlciBpcyB1c2VkIGFzIGZvbGxvdw0KDQpyZWFkLnRhYmxlKGZpbGUgPSAiZHBseXItZGF0YS9yZWFkLnRhYmxlL2ZpbGUzLnR4dCIsDQogICAgaGVhZGVyID0gRkFMU0UsDQogICAgc2tpcCA9IDUpDQojICAgICAgIFYxIFYyICBWMw0KIyAxIFN0ZXZlbiA0NSAxNzUNCiMgc2tpcCAxc3QgNSByb3dzIGFuZCBubyBoZWFkZXINCg0KcmVhZC50YWJsZShmaWxlID0gImRwbHlyLWRhdGEvcmVhZC50YWJsZS9maWxlMy50eHQiLA0KICAgIGhlYWRlciA9IFRSVUUsDQogICAgZmlsbCA9IFQpDQojIGZpbGwgbWlzc2luZyB2YWx1ZXMgYXMgTkENCiMgICAgIG5hbWUgYWdlIGhlaWdodA0KIyAxICAgSm9obiAgMTAgICAgMTUwDQojIDIgICBKYWNrICAyNyAgICAxODANCiMgMyAgIE1hcnkgIDI5ICAgIDE2Nw0KIyA0ICAgIERERCAgTkEgICAgIE5BDQojIDUgU3RldmVuICA0NSAgICAxNzUNCg0KYGBgDQoNCiMjIyByZWFkLmNzdg0KYGBge3IgaW1wb3J0IG9yZGVyIGRhdGEgYnkgcmVhZC5jc3Z9DQojIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQob3JkZXIsNSkNCm9yZGVyX3RibCA8LSB0YmxfZGYob3JkZXIpDQpoZWFkKG9yZGVyX3RibCwgNSkNCmBgYA0KDQojIyBDaGFwdGVyMiB0Ymzlr7nosaHnmoTku4vnu40NCuacrOiKguWGheWuueS7i+e7jeWmguaenOeUqGRhdGEuZnJhbWXlr7nosaHmnoTpgKDmiJB0Ymzlr7nosaENCnRibOaYr2RwbHly5a6a5LmJ55qE5pWw5o2u57G75Z6L77yM5Y+v5Lul5o6l5Y+XZGF0YS5mcmFtZSxjdWJlLHNxbA0KYGBge3IgaW1wb3J0IGRhdGEgYnkgcmVhZC50YWJsZX0NCiMgaW1wb3J0IGRhdGENCm9yZGVyIDwtIHJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL29yZGVyLmNzdiIsDQogICAgaGVhZGVyID0gVCwNCiAgICBzZXAgPSAiLCIpDQpjbGFzcyhvcmRlcikNCiMgWzFdICJkYXRhLmZyYW1lIg0KaGVhZChvcmRlcikNCnRhaWwob3JkZXIpDQoNCiMgTG9hZCBkcGx5ciBwYWNrYWdlDQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQojIGNoYW5nZSB0byB0YmwgdXNlIHRibF9kZiBmdW5jdGlvbg0Kb3JkZXJfdGJsIDwtIHRibF9kZihvcmRlcikNCmNsYXNzKG9yZGVyX3RibCkNCiMgWzFdICJ0YmxfZGYiICAgICAidGJsIiAgICAgICAgImRhdGEuZnJhbWUiDQpvcmRlcl90YmwNCg0KIyBmb3IgYSBkYXRhLmZyYW1lLCBpcyBub3QgbmVzc2FyeSB0byBjaGFuZ2UgdG8gdGJsIG9iamVjdA0KIyBmb3Igc3FsIG9iamVjdCwgY2FuIHVzZWZ1bCB0byB1c2UgZHBseXIgdG8gbWFudXB1bGF0ZSBkYXRhDQoNCiMgYW5vdGhlciB3YXkgdG8gcmVhZCBkYXRhDQpsaWJyYXJ5KHJlYWRyKQ0Kb3JkZXIgPC0gcmVhZF9jc3YoIkU6LzAzLURvd25sb2FkL2RwbHlyL2RwbHlyLWRhdGEvb3JkZXIuY3N2IikNClZpZXcob3JkZXIpDQpgYGANCg0KIyMgQ2hhcHRlcjMg5pWw5o2u562b6YCJLS1maWx0ZXLlh73mlbANCmZpbHRlcih0YmwvZGF0YS5mcmFtLCBjb25kaXRpb24pIGFuZCBvdXRwdXQgYSBkYXRhLmZyYW1lLCBmaWx0ZXIgcm93cy9vYnNlcnZhdGlvbg0KYGBge3IgZmlsdGVyIGluIGRwbHlyfQ0KIyBMb2FkIGRwbHlyIHBhY2thZ2UgaW4gYSBzYWZlciB3YXkNCmlmKCFzdXBwcmVzc1dhcm5pbmdzKHJlcXVpcmUoZHBseXIpKSkNCnsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCdkcGx5cicpDQogICAgcmVxdWlyZShkcGx5cikNCn0NCg0KZGYgPC0gZGF0YS5mcmFtZSgNCiAgY29sb3IgPSBjKCJibHVlIiwgImJsYWNrIiwgImJsdWUiLCAiYmx1ZSIsICJibGFjayIpLA0KICB2YWx1ZSA9IDE6NQ0KKQ0KdGJsIDwtIHRibF9kZihkZikNCnRibA0KIyAjIEEgdGliYmxlOiA1IMOXIDINCiMgICAgY29sb3IgdmFsdWUNCiMgICA8ZmN0cj4gPGludD4NCiMgMSAgIGJsdWUgICAgIDENCiMgMiAgYmxhY2sgICAgIDINCiMgMyAgIGJsdWUgICAgIDMNCiMgNCAgIGJsdWUgICAgIDQNCiMgNSAgYmxhY2sgICAgIDUNCg0KIyBmaWx0ZXIgYSB2YWx1ZSB0aGF0IG1hdGNoIHNvbWUgY29uZGl0aW9uDQpmaWx0ZXIodGJsLCBjb2xvciA9PSAiYmx1ZSIpDQojICMgQSB0aWJibGU6IDMgw5cgMg0KIyAgICBjb2xvciB2YWx1ZQ0KIyAgIDxmY3RyPiA8aW50Pg0KIyAxICAgYmx1ZSAgICAgMQ0KIyAyICAgYmx1ZSAgICAgMw0KIyAzICAgYmx1ZSAgICAgNA0KDQojIGZpbHRlciB2YWx1ZSBpbiAxIG9yIDQNCmZpbHRlcih0YmwsIHZhbHVlICVpbiUgYygxLDQpKQ0KIyBBIHRpYmJsZTogMiDDlyAyDQojICAgIGNvbG9yIHZhbHVlDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgICBibHVlICAgICAxDQojIDIgICBibHVlICAgICA0DQoNCiMgaW1wb3J0IGRhdGEgYW5kIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQpvcmRlciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9vcmRlci5jc3YiKQ0KaGVhZChvcmRlciw1KQ0Kb3JkZXJfdGJsIDwtIHRibF9kZihvcmRlcikNCmhlYWQob3JkZXJfdGJsLCA1KQ0KDQojIGZpbHRlciBvcmRlciBkYXRhIGlzIDIwMDktMTAtMTMgcm93cw0KZmlsdGVyKG9yZGVyX3RibCwgb3JkZXJkYXRlID09ICIyMDA5LTEwLTEzIikNCg0KIyBmaWx0ZXIgb3JkZXIgZGF0YSBpcyAyMDA5LTEwLTEzIHJvd3MgYW5kIHRvdGFsIHByaWNlIGdyZWF0ZXIgdGhhbiAxMDAgcm93cywgMSByb3cgbWF0Y2ggYW5kIGFzc2lnbiB0byBmaWx0ZXJEYXRhDQpmaWx0ZXJEYXRhIDwtIGZpbHRlcihvcmRlcl90YmwsIG9yZGVyZGF0ZSA9PSAiMjAwOS0xMC0xMyIgJiB0b3RhbHByaWNlID4gMTAwKQ0KVmlldyhmaWx0ZXJEYXRhKQ0KYGBgDQoNCiMjIENoYXB0ZXI0IOWtkOmbhumAieWPluWHveaVsC0tc2VsZWN0DQpzZWxlY3QgY29sdW1ucy92YXJpYWJsZSBieSBuYW1lL21hdGNoIHJ1bGVzDQpgYGB7ciBzZWxlY3QgZnVuY3Rpb24gaW4gZHBseXJ9DQojIExvYWQgZHBseXIgcGFja2FnZSBpbiBhIHNhZmVyIHdheQ0KaWYoIXN1cHByZXNzV2FybmluZ3MocmVxdWlyZShkcGx5cikpKQ0Kew0KICAgIGluc3RhbGwucGFja2FnZXMoJ2RwbHlyJykNCiAgICByZXF1aXJlKGRwbHlyKQ0KfQ0KDQpkZiA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0YmwgPC0gdGJsX2RmKGRmKQ0KdGJsDQoNCiMganVzdCBzZWxlY3QgY29sb3IgY29sdW1uDQpzZWxlY3QodGJsLCBjb2xvcikNCiMgQSB0aWJibGU6IDUgw5cgMQ0KIyAgICBjb2xvcg0KIyAgIDxmY3RyPg0KIyAxICAgYmx1ZQ0KIyAyICBibGFjaw0KIyAzICAgYmx1ZQ0KIyA0ICAgYmx1ZQ0KIyA1ICBibGFjaw0KDQojIHNlbGVjdCBhbGwgb3RoZXIgY29sdW1ucyBleGNlcHQgY29sb3IgY29sdW1uIGVxdWFscyBzZWxlY3QgdmFsdWUgY29sdW1uDQpzZWxlY3QodGJsLCAtY29sb3IpDQojIEEgdGliYmxlOiA1IMOXIDENCiMgICB2YWx1ZQ0KIyAgIDxpbnQ+DQojIDEgICAgIDENCiMgMiAgICAgMg0KIyAzICAgICAzDQojIDQgICAgIDQNCiMgNSAgICAgNQ0KYGBgDQoNClVzZWZ1bCBmdW5jdGlvbiB0byBzZWxlY3QNCmBgYHtyIFVzZWZ1bCBmdW5jdGlvbiB0byBzZWxlY3R9DQpzdGFydHNfd2l0aCh4LCBpZ25vcmUuY2FzZSA9IFRSVUUpICMgY29sdW1uL3ZhcmlhYmxlIHN0YXJ0IHdpdGggY2hhcnQgeA0KZW5kc193aXRoKHgsIGlnbm9yZS5jYXNlID0gVFJVRSkgIyBjb2x1bW4vdmFyaWFibGUgZW5kIHdpdGggY2hhcnQgeA0KY29udGFpbnMoeCwgaWdub3JlLmNhc2UgPSBUUlVFKSAjIGNvbHVtbi92YXJpYWJsZSBjb250YWlucyBjaGFydCB4DQptYXRjaGVzKHgsIGlnbm9yZS5jYXNlID0gVFJVRSkgICMgY29sdW1uL3ZhcmlhYmxlIG1hdGNoZXMgcmVndWxhciBleHByZXNzaW9uIHgNCm51bV9yYW5nZSgieCIsIDE6NSwgd2lkdGggPSAyKSAgIyBjb2x1bW4vdmFyaWFibGUgZnJvbSB4MDEgdG8geDA1DQpvbmVfb2YoIngiLCAieSIsICJ6IikgIyBjb2x1bW4vdmFyaWFibGUgY29udGFpbnMgaW4geCwgeSwgeg0KZXZlcnl0aGluZygpICMgYWxsIGNvbHVtbi92YXJpYWJsZQ0KDQojIGUuZy4gb3JkZXJfdGJsLCBjaGVjayBjb2x1bW4NCm5hbWVzKG9yZGVyX3RibCkNCiAjIFsxXSAiWCIgICAgICAgICAgICAgIm9yZGVyaWQiICAgICAgICJjdXN0b21lcmlkIiAgICAiY2FtcGFpZ25pZCINCiAjIFs1XSAib3JkZXJkYXRlIiAgICAgImNpdHkiICAgICAgICAgICJzdGF0ZSIgICAgICAgICAiemlwY29kZSINCiAjIFs5XSAicGF5bWVudHR5cGUiICAgInRvdGFscHJpY2UiICAgICJudW1vcmRlcmxpbmVzIiAibnVtdW5pdHMiDQoNCiMgc2VsZWN0IG9yZGVyIGRhdGEgYW5kIHRvdGFsIHByaWNlDQpkYXRlX3ByaWNlIDwtIHNlbGVjdChvcmRlcl90Ymwsb3JkZXJkYXRlLCB0b3RhbHByaWNlKQ0KZGF0ZV9wcmljZQ0KDQojIHJlbmFtZSBjb2x1bW4gbmFtZSBhdCB0aGUgc2FtZSB0aW1lDQpkYXRlX3ByaWNlMiA8LSBzZWxlY3Qob3JkZXJfdGJsLGRhdGUgPSBvcmRlcmRhdGUsIHByaWNlID0gdG90YWxwcmljZSkNCmRhdGVfcHJpY2UyDQoNCiMgc2VsZWN0IHN0YXJ0cyB3aXRoIG9yZGVyIGNvbHVtbiBuYW1lDQpTdGFydF9XaXRoX09yZGVyIDwtIHNlbGVjdChvcmRlcl90Ymwsc3RhcnRzX3dpdGgoIm9yZGVyIixpZ25vcmUuY2FzZSA9IFRSVUUpKQ0KU3RhcnRfV2l0aF9PcmRlcg0KIyBBIHRpYmJsZTogMTAwLDAwMCDDlyAyDQojICAgIG9yZGVyaWQgIG9yZGVyZGF0ZQ0KIyAgICAgIDxpbnQ+ICAgICA8ZmN0cj4NCiMgMSAgMTAwMjg1NCAyMDA5LTEwLTEzDQojIDIgIDEwMDI4NTUgMjAwOS0xMC0xMw0KIyAzICAxMDAyODU2IDIwMTEtMDYtMDINCiMgNCAgMTAwMjg1NyAyMDA5LTEwLTE0DQojIDUgIDEwMDI4ODYgMjAxMC0xMS0xOQ0KIyA2ICAxMDAyODg3IDIwMDktMTAtMTUNCiMgNyAgMTAwMjg4OCAyMDA5LTEwLTE1DQojIDggIDEwMDI4ODkgMjAwOS0xMC0xNQ0KIyA5ICAxMDAyODkwIDIwMDktMTAtMTUNCiMgMTAgMTAwMzAwNCAyMDA5LTEwLTE1DQojIC4uLiB3aXRoIDk5LDk5MCBtb3JlIHJvd3MNCg0KIyBzZWxlY3QgY29udGFpbnMgaWQgY29sdW1uIG5hbWUNCkNvbnRhaW5zX0lEIDwtIHNlbGVjdChvcmRlcl90YmwsIGNvbnRhaW5zKCJpZCIsaWdub3JlLmNhc2UgPSBUUlVFKSkNCmhlYWQoQ29udGFpbnNfSUQsNSkNCiMgQSB0aWJibGU6IDUgw5cgMw0KIyAgIG9yZGVyaWQgY3VzdG9tZXJpZCBjYW1wYWlnbmlkDQojICAgICA8aW50PiAgICAgIDxpbnQ+ICAgICAgPGludD4NCiMgMSAxMDAyODU0ICAgICAgNDU5NzggICAgICAgMjE0MQ0KIyAyIDEwMDI4NTUgICAgIDEyNTM4MSAgICAgICAyMTczDQojIDMgMTAwMjg1NiAgICAgMTAzMTIyICAgICAgIDIxNDENCiMgNCAxMDAyODU3ICAgICAxMzA5ODAgICAgICAgMjE3Mw0KIyA1IDEwMDI4ODYgICAgICA0ODU1MyAgICAgICAyMTQxDQoNCiMgcmVuYW1lIGZ1bmN0aW9uDQphcy5kYXRhLmZyYW1lKENvbnRhaW5zX0lEKQ0KIyByZW5hbWUgdGhlIG5ldyBuYW1lIG11c3QgYXQgdGhlIGxlZnQNCmFmdGVyX3JlbmFtZSA8LSByZW5hbWUoQ29udGFpbnNfSUQsIG9vSUQgPSBvcmRlcmlkLCBvb0lEID0gY3VzdG9tZXJpZCwgb29DQUlEID0gIGNhbXBhaWduaWQpDQpoZWFkKENvbnRhaW5zX0lELDUpDQojIEEgdGliYmxlOiA1IMOXIDMNCiMgICBvcmRlcmlkIGN1c3RvbWVyaWQgY2FtcGFpZ25pZA0KIyAgICAgPGludD4gICAgICA8aW50PiAgICAgIDxpbnQ+DQojIDEgMTAwMjg1NCAgICAgIDQ1OTc4ICAgICAgIDIxNDENCiMgMiAxMDAyODU1ICAgICAxMjUzODEgICAgICAgMjE3Mw0KIyAzIDEwMDI4NTYgICAgIDEwMzEyMiAgICAgICAyMTQxDQojIDQgMTAwMjg1NyAgICAgMTMwOTgwICAgICAgIDIxNzMNCiMgNSAxMDAyODg2ICAgICAgNDg1NTMgICAgICAgMjE0MQ0KDQojIGFmdGVyIHJlbmFtZSByZXR1cm5zIGEgbmV3IHRibCwgdGhlIG9yaWdpbiBDb250YWluc19JRCB3aWxsIG5vdCBiZSBjaGFuZ2VkDQpoZWFkKGFmdGVyX3JlbmFtZSw1KQ0KIyBBIHRpYmJsZTogNSDDlyAzDQojICAgICAgb29JRCAgIG9vSUQgb29DQUlEDQojICAgICA8aW50PiAgPGludD4gIDxpbnQ+DQojIDEgMTAwMjg1NCAgNDU5NzggICAyMTQxDQojIDIgMTAwMjg1NSAxMjUzODEgICAyMTczDQojIDMgMTAwMjg1NiAxMDMxMjIgICAyMTQxDQojIDQgMTAwMjg1NyAxMzA5ODAgICAyMTczDQojIDUgMTAwMjg4NiAgNDg1NTMgICAyMTQxDQojIHRoaXMgd29ya3MgaW4gdGhlIGNvZGUgYmVsb3cNCmhlYWQocmVuYW1lKGlyaXMsIHB0ID0gUGV0YWwuTGVuZ3RoKSw1KQ0KDQojIGUuZy4gd2l0aCBzZWxlY3QgZnJvbSA/IHJlbmFtZQ0KaXJpcyA8LSB0YmxfZGYoaXJpcykgIyBzbyBpdCBwcmludHMgYSBsaXR0bGUgbmljZXINCnNlbGVjdChpcmlzLCBzdGFydHNfd2l0aCgiUGV0YWwiKSkNCnNlbGVjdChpcmlzLCBlbmRzX3dpdGgoIldpZHRoIikpDQpzZWxlY3QoaXJpcywgY29udGFpbnMoImV0YWwiKSkNCnNlbGVjdChpcmlzLCBtYXRjaGVzKCIudC4iKSkNCnNlbGVjdChpcmlzLCBQZXRhbC5MZW5ndGgsIFBldGFsLldpZHRoKQ0KdmFycyA8LSBjKCJQZXRhbC5MZW5ndGgiLCAiUGV0YWwuV2lkdGgiKQ0Kc2VsZWN0KGlyaXMsIG9uZV9vZih2YXJzKSkNCg0KZGYgPC0gYXMuZGF0YS5mcmFtZShtYXRyaXgocnVuaWYoMTAwKSwgbnJvdyA9IDEwKSkNCmRmIDwtIHRibF9kZihkZltjKDMsIDQsIDcsIDEsIDksIDgsIDUsIDIsIDYsIDEwKV0pDQpzZWxlY3QoZGYsIFY0OlY2KQ0Kc2VsZWN0KGRmLCBudW1fcmFuZ2UoIlYiLCA0OjYpKQ0KDQojIERyb3AgdmFyaWFibGVzDQpzZWxlY3QoaXJpcywgLXN0YXJ0c193aXRoKCJQZXRhbCIpKQ0Kc2VsZWN0KGlyaXMsIC1lbmRzX3dpdGgoIldpZHRoIikpDQpzZWxlY3QoaXJpcywgLWNvbnRhaW5zKCJldGFsIikpDQpzZWxlY3QoaXJpcywgLW1hdGNoZXMoIi50LiIpKQ0Kc2VsZWN0KGlyaXMsIC1QZXRhbC5MZW5ndGgsIC1QZXRhbC5XaWR0aCkNCg0KIyBSZW5hbWUgdmFyaWFibGVzOg0KIyAqIHNlbGVjdCgpIGtlZXBzIG9ubHkgdGhlIHZhcmlhYmxlcyB5b3Ugc3BlY2lmeQ0Kc2VsZWN0KGlyaXMsIHBldGFsX2xlbmd0aCA9IFBldGFsLkxlbmd0aCkNCiMgUmVuYW1pbmcgbXVsdGlwbGUgdmFyaWFibGVzIHVzZXMgYSBwcmVmaXg6DQpzZWxlY3QoaXJpcywgcGV0YWwgPSBzdGFydHNfd2l0aCgiUGV0YWwiKSkNCg0KIyBSZW9yZGVyIHZhcmlhYmxlczoga2VlcCB0aGUgdmFyaWFibGUgIlNwZWNpZXMiIGluIHRoZSBmcm9udA0Kc2VsZWN0KGlyaXMsIFNwZWNpZXMsIGV2ZXJ5dGhpbmcoKSkNCg0KIyAqIHJlbmFtZSgpIGtlZXBzIGFsbCB2YXJpYWJsZXMNCnJlbmFtZShpcmlzLCBwZXRhbF9sZW5ndGggPSBQZXRhbC5MZW5ndGgpDQoNCiMgUHJvZ3JhbW1pbmcgd2l0aCBzZWxlY3QgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpzZWxlY3RfKGlyaXMsIH5QZXRhbC5MZW5ndGgpDQpzZWxlY3RfKGlyaXMsICJQZXRhbC5MZW5ndGgiKQ0Kc2VsZWN0XyhpcmlzLCBsYXp5ZXZhbDo6aW50ZXJwKH5tYXRjaGVzKHgpLCB4ID0gIi50LiIpKQ0Kc2VsZWN0XyhpcmlzLCBxdW90ZSgtUGV0YWwuTGVuZ3RoKSwgcXVvdGUoLVBldGFsLldpZHRoKSkNCnNlbGVjdF8oaXJpcywgLmRvdHMgPSBsaXN0KHF1b3RlKC1QZXRhbC5MZW5ndGgpLCBxdW90ZSgtUGV0YWwuV2lkdGgpKSkNCmBgYA0KDQojIyBDaGFwdGVyNSDmlbDmja7nmoTmjpLluo8tLWFycmFuZ2Xlh73mlbANCnRyYWRpdGlvbmFsIG1ldGhvZDogb3JkZXIgZnVuY3Rpb24NCmBgYHtyIHVzZSBvcmRlciB0byBvcmRlcn0NCiMgTG9hZCBkcGx5ciBwYWNrYWdlIGluIGEgc2FmZXIgd2F5DQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQoNCmRmMSA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0YmwgPC0gdGJsX2RmKGRmMSkNCnRibA0KIyBBIHRpYmJsZTogNSDDlyAyDQojICAgIGNvbG9yIHZhbHVlDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgICBibHVlICAgICAxDQojIDIgIGJsYWNrICAgICAyDQojIDMgICBibHVlICAgICAzDQojIDQgICBibHVlICAgICA0DQojIDUgIGJsYWNrICAgICA1DQoNCiMgb3JkZXIgdXNlIGluZGV4DQpkZl9vcmRlciA8LSBvcmRlcihkZjEkY29sb3IpDQpkZl9vcmRlcg0KIyBbMV0gMiA1IDEgMyA0DQpkZjFbZGZfb3JkZXIsXQ0KIyAgIGNvbG9yIHZhbHVlDQojIDIgYmxhY2sgICAgIDINCiMgNSBibGFjayAgICAgNQ0KIyAxICBibHVlICAgICAxDQojIDMgIGJsdWUgICAgIDMNCiMgNCAgYmx1ZSAgICAgNA0KDQojIHVzZSBhcnJhbmdlIHRvIG9yZGVyIGEgZGF0YSBmcmFtZS90YmwsIGRlZmF1bHQgaXMgYWVzYywgMSB0byAzDQphcnJhbmdlKGRmMSwgY29sb3IpDQojIHVzZSBkZXNjIHRvIG9yZGVyIGJ5IDMgdG8gMQ0KYXJyYW5nZShkZjEsIGRlc2MoY29sb3IpKQ0KDQojIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQob3JkZXIsNSkNCm9yZGVyX3RibCA8LSB0YmxfZGYob3JkZXIpDQpoZWFkKG9yZGVyX3RibCwgNSkNCg0KIyBvcmRlciBieSBkYXRlDQp0YmwgPC0gc2VsZWN0KG9yZGVyX3RibCwgb2RhdGUgPSBvcmRlcmRhdGUsIG9wcmljZSA9IHRvdGFscHJpY2UpDQphcnJhbmdlKHRibCwgb2RhdGUpDQojIEEgdGliYmxlOiAxMDAsMDAwIMOXIDINCiMgICAgICAgICBvZGF0ZSBvcHJpY2UNCiMgICAgICAgIDxmY3RyPiAgPGRibD4NCiMgMSAgMjAwOS0xMC0wNCAgICAyMDANCiMgMiAgMjAwOS0xMC0wNCAgICAxMjANCiMgMyAgMjAwOS0xMC0wNCAgICAxMDANCiMgNCAgMjAwOS0xMC0wNCAgICAxMDANCiMgNSAgMjAwOS0xMC0wNCAgICAgNzANCiMgNiAgMjAwOS0xMC0wNCAgICAgNTANCiMgNyAgMjAwOS0xMC0wNCAgICAgNTANCiMgOCAgMjAwOS0xMC0wNCAgICAgNDANCiMgOSAgMjAwOS0xMC0wNCAgICAgNDANCiMgMTAgMjAwOS0xMC0wNCAgICAgNDANCiMgLi4uIHdpdGggOTksOTkwIG1vcmUgcm93cw0KDQojIG9yZGVyIGJ5IGRhdGUgJiBieSBwcmljZSBkZXNjIDMgdG8gMQ0KYXJyYW5nZSh0YmwsIG9kYXRlLCBkZXNjKG9wcmljZSkpDQojIEEgdGliYmxlOiAxMDAsMDAwIMOXIDINCiMgICAgICAgICBvZGF0ZSBvcHJpY2UNCiMgICAgICAgIDxmY3RyPiAgPGRibD4NCiMgMSAgMjAwOS0xMC0wNCAgICAyMDANCiMgMiAgMjAwOS0xMC0wNCAgICAxMjANCiMgMyAgMjAwOS0xMC0wNCAgICAxMDANCiMgNCAgMjAwOS0xMC0wNCAgICAxMDANCiMgNSAgMjAwOS0xMC0wNCAgICAgNzANCiMgNiAgMjAwOS0xMC0wNCAgICAgNTANCiMgNyAgMjAwOS0xMC0wNCAgICAgNTANCiMgOCAgMjAwOS0xMC0wNCAgICAgNDANCiMgOSAgMjAwOS0xMC0wNCAgICAgNDANCiMgMTAgMjAwOS0xMC0wNCAgICAgNDANCiMgLi4uIHdpdGggOTksOTkwIG1vcmUgcm93cw0KYGBgDQoNCiMjIENoYXB0ZXI2IOaVsOaNruaJqeWxlS0tbXV0YXRl5Ye95pWwDQrmlbDmja7mianlsZXvvIzkv53nlZnljp/mnaXnmoTlj5jph4/jgIHliJfnmoTln7rnoYDkuIrlop7liqDlj5jph4/miJbogIXliJcNCmBgYHtyIG11dGF0ZSBmdW5jdGlvbn0NCiMgTG9hZCBkcGx5ciBwYWNrYWdlIGluIGEgc2FmZXIgd2F5DQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQoNCmRmMSA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0YmwgPC0gdGJsX2RmKGRmMSkNCnRibA0KIyBBIHRpYmJsZTogNSDDlyAyDQojICAgIGNvbG9yIHZhbHVlDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgICBibHVlICAgICAxDQojIDIgIGJsYWNrICAgICAyDQojIDMgICBibHVlICAgICAzDQojIDQgICBibHVlICAgICA0DQojIDUgIGJsYWNrICAgICA1DQoNCiMgYWRkIGRvdWJsZSBjb2x1bW4NCm11dGF0ZSh0YmwsIGRvdWJsZSA9IDIgKiB2YWx1ZSkNCiMgQSB0aWJibGU6IDUgw5cgMw0KIyAgICBjb2xvciB2YWx1ZSBkb3VibGUNCiMgICA8ZmN0cj4gPGludD4gIDxkYmw+DQojIDEgICBibHVlICAgICAxICAgICAgMg0KIyAyICBibGFjayAgICAgMiAgICAgIDQNCiMgMyAgIGJsdWUgICAgIDMgICAgICA2DQojIDQgICBibHVlICAgICA0ICAgICAgOA0KIyA1ICBibGFjayAgICAgNSAgICAgMTANCg0KIyBhZGQgZG91YmxlIGNvbHVtbiBhbmQgcXVhZHJ1cGxlIGNvbHVtbg0KbXV0YXRlKHRibCwgZG91YmxlID0gMiAqIHZhbHVlLCBxdWFkcnVwbGUgPSA0ICogdmFsdWUpDQojIEEgdGliYmxlOiA1IMOXIDQNCiMgICAgY29sb3IgdmFsdWUgZG91YmxlIHF1YWRydXBsZQ0KIyAgIDxmY3RyPiA8aW50PiAgPGRibD4gICAgIDxkYmw+DQojIDEgICBibHVlICAgICAxICAgICAgMiAgICAgICAgIDQNCiMgMiAgYmxhY2sgICAgIDIgICAgICA0ICAgICAgICAgOA0KIyAzICAgYmx1ZSAgICAgMyAgICAgIDYgICAgICAgIDEyDQojIDQgICBibHVlICAgICA0ICAgICAgOCAgICAgICAgMTYNCiMgNSAgYmxhY2sgICAgIDUgICAgIDEwICAgICAgICAyMA0KDQojIHVzZSBvcmRlciBkYXRhIHNldCB0byBtdXRhdGUgeWVhciwgbW9udGggYW5kIGRhdGUNCiMgaW1wb3J0IGRhdGEgYW5kIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQpvcmRlciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9vcmRlci5jc3YiKQ0KaGVhZChvcmRlciw1KQ0Kb3JkZXJfdGJsIDwtIHRibF9kZihvcmRlcikNCmhlYWQob3JkZXJfdGJsLCA1KQ0KdGJsIDwtIHNlbGVjdChvcmRlcl90YmwsIG9kYXRlID0gb3JkZXJkYXRlLCBvcHJpY2UgPSB0b3RhbHByaWNlKQ0KdGJsIDwtIGFycmFuZ2UodGJsLCBvZGF0ZSwgZGVzYyhvcHJpY2UpKQ0KaGVhZCh0YmwsIDUpDQojICMgQSB0aWJibGU6IDUgw5cgMg0KIyAgICAgICAgb2RhdGUgb3ByaWNlDQojICAgICAgIDxmY3RyPiAgPGRibD4NCiMgMSAyMDA5LTEwLTA0ICAgIDIwMA0KIyAyIDIwMDktMTAtMDQgICAgMTIwDQojIDMgMjAwOS0xMC0wNCAgICAxMDANCiMgNCAyMDA5LTEwLTA0ICAgIDEwMA0KIyA1IDIwMDktMTAtMDQgICAgIDcwDQoNCiMgbXV0YXRlDQp0YmxfTmV3IDwtIG11dGF0ZSh0YmwsIG9ZZWFyID0gc3Vic3RyKG9kYXRlLCAxLCA0KSwgb01vbnRoID0gc3Vic3RyKG9kYXRlLCA2LCA3KSxvRGF0ZSA9IHN1YnN0cihvZGF0ZSwgOSwgMTApKQ0KaGVhZCh0YmxfTmV3LDUpDQojIEEgdGliYmxlOiA1IMOXIDUNCiMgICAgICAgIG9kYXRlIG9wcmljZSBvWWVhciBvTW9udGggb0RhdGUNCiMgICAgICAgPGZjdHI+ICA8ZGJsPiA8Y2hyPiAgPGNocj4gPGNocj4NCiMgMSAyMDA5LTEwLTA0ICAgIDIwMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgMiAyMDA5LTEwLTA0ICAgIDEyMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgMyAyMDA5LTEwLTA0ICAgIDEwMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgNCAyMDA5LTEwLTA0ICAgIDEwMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgNSAyMDA5LTEwLTA0ICAgICA3MCAgMjAwOSAgICAgMTAgICAgMDQNCg0KIyB0cmFuc211dGUNCiMgTXV0YXRlIGFkZHMgbmV3IHZhcmlhYmxlcyBhbmQgcHJlc2VydmVzIGV4aXN0aW5nOw0KIyB0cmFuc211dGUgZHJvcHMgZXhpc3RpbmcgdmFyaWFibGVzLg0KZGYxIDwtIGRhdGEuZnJhbWUoDQogIGNvbG9yID0gYygiYmx1ZSIsICJibGFjayIsICJibHVlIiwgImJsdWUiLCAiYmxhY2siKSwNCiAgdmFsdWUgPSAxOjUNCikNCnRibF90cmFuc211dGUgPC0gdGJsX2RmKGRmMSkNCnRibF90cmFuc211dGUNCiMgQSB0aWJibGU6IDUgw5cgMg0KIyAgICBjb2xvciB2YWx1ZQ0KIyAgIDxmY3RyPiA8aW50Pg0KIyAxICAgYmx1ZSAgICAgMQ0KIyAyICBibGFjayAgICAgMg0KIyAzICAgYmx1ZSAgICAgMw0KIyA0ICAgYmx1ZSAgICAgNA0KIyA1ICBibGFjayAgICAgNQ0KDQp0cmFuc211dGUodGJsX3RyYW5zbXV0ZSwgZG91YmxlID0gMiAqIHZhbHVlLCBxdWFkcnVwbGUgPSA0ICogdmFsdWUpDQojIEEgdGliYmxlOiA1IMOXIDINCiMgICBkb3VibGUgcXVhZHJ1cGxlDQojICAgIDxkYmw+ICAgICA8ZGJsPg0KIyAxICAgICAgMiAgICAgICAgIDQNCiMgMiAgICAgIDQgICAgICAgICA4DQojIDMgICAgICA2ICAgICAgICAxMg0KIyA0ICAgICAgOCAgICAgICAgMTYNCiMgNSAgICAgMTAgICAgICAgIDIwDQpgYGANCg0KIyMgQ2hhcHRlcjcg5pWw5o2u5rGH5oC7LS1zdW1tYXJpc2Xlh73mlbANCuaVsOaNruaxh+aAuy3lsIblpJrkuKrlgLzmsYfmgLvkuLrkuIDkuKrmlbDmja7lgLwNCmBgYHtyIHN1bW1hcmlzZX0NCmRmMSA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0Ymxfc3VtbWFyaXNlIDwtIHRibF9kZihkZjEpDQoNCnN1bW1hcmlzZSh0Ymxfc3VtbWFyaXNlLCB0b3RhbCA9IHN1bSh2YWx1ZSkpDQojIEEgdGliYmxlOiAxIMOXIDENCiMgICB0b3RhbA0KIyAgIDxpbnQ+DQojIDEgICAgMTUNCg0KIyBtdWx0aSBwYXJhbWV0ZXINCnN1bW1hcmlzZSh0Ymxfc3VtbWFyaXNlLCB0b3RhbF92YWx1ZSA9IHN1bSh2YWx1ZSksIG1lYW5fdmFsdWUgPSBtZWFuKHZhbHVlKSwgc2RfdmFsdWUgPSBzZCh2YWx1ZSkpDQojIEEgdGliYmxlOiAxIMOXIDMNCiMgICB0b3RhbF92YWx1ZSBtZWFuX3ZhbHVlIHNkX3ZhbHVlDQojICAgICAgICAgPGludD4gICAgICA8ZGJsPiAgICA8ZGJsPg0KIyAxICAgICAgICAgIDE1ICAgICAgICAgIDMgMS41ODExMzkNCg0KIyB1c2Ugb3JkZXIgZGF0YSBzZXQgdG8gc3VtbWFyaXNlDQojIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQob3JkZXIsNSkNCm9yZGVyX3RibCA8LSB0YmxfZGYob3JkZXIpDQpoZWFkKG9yZGVyX3RibCwgNSkNCnRibCA8LSBzZWxlY3Qob3JkZXJfdGJsLCBvZGF0ZSA9IG9yZGVyZGF0ZSwgb3ByaWNlID0gdG90YWxwcmljZSkNCiMgdGJsIDwtIGFycmFuZ2UodGJsLCBvZGF0ZSwgZGVzYyhvcHJpY2UpKQ0Kc3VtbWFyaXNlKHRibCwgbWF4ID0gbWF4KG9wcmljZSksDQogICAgICAgICAgICAgIG1pbiA9IG1pbihvcHJpY2UpLA0KICAgICAgICAgICAgICBtZWFuID0gbWVhbihvcHJpY2UpKQ0KIyBBIHRpYmJsZTogMSDDlyAzDQojICAgICBtYXggICBtaW4gICAgIG1lYW4NCiMgICA8ZGJsPiA8ZGJsPiAgICA8ZGJsPg0KIyAxICA2NzgwICAgICAwIDYwLjc3NzczDQoNCmBgYA0Kc3VtbWFyaXNlKCnkuK3nmoTmsYfmgLvlh73mlbDlsIbkuIDliJflgLzovazmjaLkuLrkuIDkuKrljZXni6znmoTlgLzovpPlh7oNClLoh6rluKbnmoTnu5/orqHlh73mlbDpg73mmK/lj6/ku6Xkvb/nlKjnmoQNCm1pbigpLCBtYXgoKSwgbWVhbigpLCBzdW0oKSwgc2QoKSwgbWVkaWFuKCksIElRUigpDQoNCuatpOWklu+8jGRwbHly6L+Y5o+Q5L6b5LqG5LiA5Lqb5YW25LuW5Lya55So5Yiw55qE5Ye95pWwDQpuKCk66KeC5rWL5YC855qE5Liq5pWwDQpuX2Rpc3RpbmN0KHgpOuS4jeebuOWQjOeahOingua1i+WAvOeahOS4quaVsA0KZmlyc3QoeCksbGFzdCh4KeWSjG50aCh4LCBuKeiOt+WPluesrOS4gOS4qu+8jOacgOWQjuS4gOS4qu+8jOWSjOesrG7kuKrmlbDmja4NCg0KYGBge3IgZmlyc3QgYW5kIGxhc3QgdmFsdWV9DQpzdW1tYXJpc2UodGJsLCBmaXJzdCA9IGZpcnN0KG9kYXRlKSwgbGFzdCA9IGxhc3Qob2RhdGUpKQ0KIyBBIHRpYmJsZTogMSDDlyAyDQojICAgICAgICBmaXJzdCAgICAgICBsYXN0DQojICAgICAgIDxmY3RyPiAgICAgPGZjdHI+DQojIDEgMjAwOS0xMC0xMyAyMDE0LTA0LTI4DQpgYGANCg0KIyMgQ2hhcHRlcjgg5pWw5o2u6L+e5o6lLS1qb2lu5Ye95pWwDQpkcGx5ciBhZHZhbmNlZCBmdW5jdGlvbjoNCi0gZGF0YSBzZXQgam9pbi9jb25uZWN0aW9uLCBsaWtlIGV4Y2VsIHZsb29rdXAgZnVuY3Rpb24NCi0gZ3JvdXBfYnkNCi0gcGlwZSBmdW5jdGlvbjogJT4lDQotIG90aGVyIGZ1bmN0aW9uOiBkbywgcGx5cjo6Y29sd2lzZQ0KLSBteXNxbCBkYXRhYmFzZSBjb25uZWN0aW9uDQoNCmBgYHtyIGpvaW59DQp4IDwtIGRhdGEuZnJhbWUobmFtZSA9IGMoIkpvaG4iLCAiUGF1bCIsICJHZW9yZ2UiLCAiUmluZ28iLCAiU3R1YXJ0IiwgIlNpcWluIiksDQogICAgICAgICAgICAgICAgaW5zdHJ1bWVudCA9IGMoImd1aXRhciIsICJiYXNzIiwgImd1aXRhciIsICJkcnVtcyIsICJiYXNzIiwgImRydW1zIikpDQp4DQojICAgICBuYW1lIGluc3RydW1lbnQNCiMgMSAgIEpvaG4gICAgIGd1aXRhcg0KIyAyICAgUGF1bCAgICAgICBiYXNzDQojIDMgR2VvcmdlICAgICBndWl0YXINCiMgNCAgUmluZ28gICAgICBkcnVtcw0KIyA1IFN0dWFydCAgICAgICBiYXNzDQojIDYgIFNpcWluICAgICAgZHJ1bXMNCnkgPC0gZGF0YS5mcmFtZShuYW1lID0gYygiSm9obiIsICJQYXVsIiwgIkdlb3JnZSIsICJSaW5nbyIsICJCcmlhbiIpLA0KICAgICAgICAgICAgICAgIGJhbmQgPSBjKFQsIFQsIFQsIFQsIFQpKQ0KeQ0KIyAgICAgbmFtZSBiYW5kDQojIDEgICBKb2huIFRSVUUNCiMgMiAgIFBhdWwgVFJVRQ0KIyAzIEdlb3JnZSBUUlVFDQojIDQgIFJpbmdvIFRSVUUNCiMgNSAgQnJpYW4gVFJVRQ0KDQojIGxlZnRfam9pbiBsaWtlIGV4Y2VsIHZsb29rdXAsIGFsbCB2YWx1ZSBpbiBsZWZ0IHRhYmxlIHdpbGwgcmVtYWluLCBidXQgbm90IG1hdGNoIHZhbHVlIGluIHJpZ2h0IHRhYmxlIHdpbGwgYmUgc2V0IE5BDQpsZWZ0X2pvaW4oeCwgeSwgYnkgPSAibmFtZSIpDQojICAgICBuYW1lIGluc3RydW1lbnQgYmFuZA0KIyAxICAgSm9obiAgICAgZ3VpdGFyIFRSVUUNCiMgMiAgIFBhdWwgICAgICAgYmFzcyBUUlVFDQojIDMgR2VvcmdlICAgICBndWl0YXIgVFJVRQ0KIyA0ICBSaW5nbyAgICAgIGRydW1zIFRSVUUNCiMgNSBTdHVhcnQgICAgICAgYmFzcyAgIE5BDQojIDYgIFNpcWluICAgICAgZHJ1bXMgICBOQQ0KDQojIGlubmVyX2pvaW4sIGp1c3QgcmVtYWluIGxlZnQgYW5kIHJpZ2h0IHRhYmxlIG1hdGNoIHZhbHVlLA0KIyBhbmQgYWRkIGNvbHVtbihyaWdodCB0YWJsZSBkYXRhKSBpbiBsZWZ0IHRhYmxlDQojIGFuZCBub3QgbWF0Y2ggdmFsdWUgaW4gbGVmdCB0YWJsZSB3aWxsIGJlIGRpc2NhcmRlZA0KaW5uZXJfam9pbih4LCB5LCBieSA9ICJuYW1lIikNCiMgICAgIG5hbWUgaW5zdHJ1bWVudCBiYW5kDQojIDEgICBKb2huICAgICBndWl0YXIgVFJVRQ0KIyAyICAgUGF1bCAgICAgICBiYXNzIFRSVUUNCiMgMyBHZW9yZ2UgICAgIGd1aXRhciBUUlVFDQojIDQgIFJpbmdvICAgICAgZHJ1bXMgVFJVRQ0KDQojIHNlbWlfam9pbiwganVzdCByZW1haW4gbGVmdCB0YWJsZSB0aGF0IG1hdGNoZXMgdGhlIHZhbHVlIGluIHJpZ2h0IHRhYmxlLCBhbmQgcmlnaHQgdGFibGUgdmFsdWUgd2lsbCBub3QgdXNlZA0Kc2VtaV9qb2luKHgsIHksIGJ5ID0gIm5hbWUiKQ0KIyAgICAgbmFtZSBpbnN0cnVtZW50DQojIDEgICBKb2huICAgICBndWl0YXINCiMgMiAgIFBhdWwgICAgICAgYmFzcw0KIyAzIEdlb3JnZSAgICAgZ3VpdGFyDQojIDQgIFJpbmdvICAgICAgZHJ1bXMNCg0KIyBhbnRpX2pvaW4sIGp1c3QgY29udmVydCB3aXRoIHNlbWlfam9pbiwganVzdCBrZWVwIG1hdGNoIHZhbHVlcyBpbiByaWdodCB0YWJsZQ0KYW50aV9qb2luKHgsIHksIGJ5ID0gIm5hbWUiKQ0KIyAgICAgbmFtZSBpbnN0cnVtZW50DQojIDEgIFNpcWluICAgICAgZHJ1bXMNCiMgMiBTdHVhcnQgICAgICAgYmFzcw0KDQojIHVzZSBvcmRlciBhbmQgY3VzdGltZXIgZGF0YSBzZXQgdG8gam9pbg0KIyBpbXBvcnQgZGF0YSBhbmQgY2hhbmdlIHRvIHRibCBvYmplY3QNCmRmX29yZGVyIDwtIHJlYWQuY3N2KCJkcGx5ci1kYXRhL29yZGVyLmNzdiIpDQpkZl9jdXN0b21lciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9jdXN0b21lci5jc3YiKQ0KaGVhZChkZl9vcmRlciw1KQ0KaGVhZChkZl9jdXN0b21lciw1KQ0KDQp0Ymxfb3JkZXIgPC0gdGJsX2RmKGRmX29yZGVyKQ0KdGJsX2N1c3RvbWVyIDwtIHRibF9kZihkZl9jdXN0b21lcikNCg0Kc19vcmRlciA8LSBzZWxlY3QodGJsX29yZGVyLCBvZGF0ZSA9IG9yZGVyZGF0ZSwgb2N1c3RfaWQgPSBjdXN0b21lcmlkKQ0Kc19jdXN0b21lciA8LSBzZWxlY3QodGJsX2N1c3RvbWVyLCBvY3VzdF9pZCA9IGN1c3RvbWVyaWQsIGdlbmRlciwgZmlyc3RuYW1lLGxhc3RuYW1lID1MYXN0bmFtZSkNCg0KYXJyYW5nZShsZWZ0X2pvaW4oc19vcmRlciwgc19jdXN0b21lciwgYnkgPSAib2N1c3RfaWQiKSwgZmlyc3RuYW1lKQ0KYGBgDQoNCiMjIENoYXB0ZXI5IOWIhuexu+axh+aAuyAtLSBncm91cF9ieQ0K5YiG57G75rGH5oC7IC0tIGdyb3VwX2J5DQpgYGB7ciBncm91cF9ieSBmdW5jdGlvbn0NCiNzdW1tYXJ5IGJ5IHllYXItLUdyb3VwLXdpc2Ugc3VtbWFyeQ0KIyBncm91cF9ieSgp6L2s5Y+Y5oiQ5LiAIOS4quWIhuWlvee7hOeahOaVsOaNruahhg0KDQpkZjEgPC0gZGF0YS5mcmFtZSgNCiAgY29sb3IgPSBjKCJibHVlIiwgImJsYWNrIiwgImJsdWUiLCAiYmx1ZSIsICJibGFjayIpLA0KICB2YWx1ZSA9IDE6NQ0KKQ0Kc3VtbWFyaXNlKGRmMSwgdG90YWwgPXN1bSh2YWx1ZSkpDQojIGp1c3QgZ2V0IG9uZSBzdW1hcmlzZWQgZGF0YSB0b3RhbA0KIyAgIHRvdGFsDQojIDEgICAgMTUNCg0KIyBncm91cCBieSBjb2xvcg0KYnlfY29sb3IgPC0gZ3JvdXBfYnkoZGYxLCBjb2xvcikNCiMgdGhlbiBzdW1tYXJpc2UgYnkgZ3JvdXANCnN1bW1hcmlzZShieV9jb2xvciwgdG90YWwgPSBzdW0odmFsdWUpKQ0KIyBBIHRpYmJsZTogMiDDlyAyDQojICAgIGNvbG9yIHRvdGFsDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgIGJsYWNrICAgICA3DQojIDIgICBibHVlICAgICA4DQoNCg0KIyB1c2Ugb3JkZXIgZGF0YSBzZXQNCiMgaW1wb3J0IGRhdGEgYW5kIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQpkZl9vcmRlciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9vcmRlci5jc3YiKQ0KaGVhZChkZl9vcmRlciw1KQ0KDQp0Ymxfb3JkZXIgPC0gdGJsX2RmKGRmX29yZGVyKQ0KIyB0YmxfY3VzdG9tZXIgPC0gdGJsX2RmKGRmX2N1c3RvbWVyKQ0KDQpzX29yZGVyIDwtIHNlbGVjdCh0Ymxfb3JkZXIsIG9kYXRlID0gb3JkZXJkYXRlLCBvcHJpY2UgPSB0b3RhbHByaWNlKQ0KDQojIG11dGF0ZSB5ZWFyIGFuZCBtb250aCBjb2x1bW4NCm1fb3JkZXIgPC0gbXV0YXRlKHNfb3JkZXIsDQogICAgICAgICAgICAgICAgICBveWVhciA9IHN1YnN0cihvZGF0ZSwgMSwgNCksDQogICAgICAgICAgICAgICAgICBvbW9udGggPSBzdWJzdHIob2RhdGUsIDYsIDcpKQ0KaGVhZChtX29yZGVyLCA1KQ0KDQojIGdyb3VwIGJ5IHllYXINCm1fb3JkZXJfeWVhciA8LSBncm91cF9ieShtX29yZGVyLCBveWVhcikNCmhlYWQobV9vcmRlcl95ZWFyKQ0KIyBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzYgeCA0XQ0KIyBHcm91cHM6IG95ZWFyIFszXQ0KIw0KIyAgICAgICAgb2RhdGUgb3ByaWNlIG95ZWFyIG9tb250aA0KIyAgICAgICA8ZmN0cj4gIDxkYmw+IDxjaHI+ICA8Y2hyPg0KIyAxIDIwMDktMTAtMTMgMTkwLjAwICAyMDA5ICAgICAxMA0KIyAyIDIwMDktMTAtMTMgIDEwLjAwICAyMDA5ICAgICAxMA0KIyAzIDIwMTEtMDYtMDIgIDM1LjIyICAyMDExICAgICAwNg0KIyA0IDIwMDktMTAtMTQgIDEwLjAwICAyMDA5ICAgICAxMA0KIyA1IDIwMTAtMTEtMTkgIDEwLjAwICAyMDEwICAgICAxMQ0KIyA2IDIwMDktMTAtMTUgIDEwLjAwICAyMDA5ICAgICAxMA0KDQojIHN1bW1hcnkgeWVhcmx5IHByaWNlIGFuZCBhdmVyYWdlIHByaWNlLCBhbmQgbWF4IG1vbnRoIGZvciBjaGVjayBkYXRhIHBlcmlvZCh5ZWFyIDIwMTQganVzdCBoYXZlIDUgbW9udGgpDQojIHN1bW1hcmlzZSBzdXBwb3J0IG11bHRpIHBhcmFtZXRlcg0Kc3VtbWFyaXNlKG1fb3JkZXJfeWVhciwNCiAgICAgICAgICB5ZWFybHlfcHJpY2UgPSBzdW0ob3ByaWNlKSwNCiAgICAgICAgICBhdmVyYWdlX3ByaWNlID0gbWVhbihvcHJpY2UpLA0KICAgICAgICAgIE1heF9Nb250aCA9IG1heChvbW9udGgpKQ0KIyBBIHRpYmJsZTogNiDDlyA0DQojICAgb3llYXIgeWVhcmx5X3ByaWNlIGF2ZXJhZ2VfcHJpY2UgYG1heChvbW9udGgpYA0KIyAgIDxjaHI+ICAgICAgICA8ZGJsPiAgICAgICAgIDxkYmw+ICAgICAgICAgPGNocj4NCiMgMSAgMjAwOSAgICAgMjYyNjI3LjUgICAgICAzNC4xMzg1MCAgICAgICAgICAgIDEyDQojIDIgIDIwMTAgICAgIDk2NzQyOS4yICAgICAgNTIuMjM5ODIgICAgICAgICAgICAxMg0KIyAzICAyMDExICAgIDEzODA2MzYuNiAgICAgIDUxLjM1MzQyICAgICAgICAgICAgMTINCiMgNCAgMjAxMiAgICAxNDA0MTEzLjEgICAgICA2OC40MDk5MCAgICAgICAgICAgIDEyDQojIDUgIDIwMTMgICAgMTYzMzAwNC44ICAgICAgNzYuNzEwMTEgICAgICAgICAgICAxMg0KIyA2ICAyMDE0ICAgICA0Mjk5NjIuMCAgICAgIDg0LjQ3MTkwICAgICAgICAgICAgMDUNCmBgYA0KDQojIyBDaGFwdGVyMTAg566h6YGT5Ye95pWwDQolPiUgb3IgJS4lIHVzZSB0aGUgcHJldmlvdXMgZnVuY3Rpb24obGVmdCkncyBvdXQgcHV0IGFzIHRoZSBuZXh0IGZ1bmN0aW9uKHJpZ2h0KSdzIGlucHV0Lg0KYGBge3IgcGlwZSBmdW5jdGlvbn0NCjE6NSAlPiUgbWVhbigpDQojIFsxXSAzDQoxOjUgJT4lIG1lYW4oLikgJT4lIHNxcnQoKQ0KIyBbMV0gMS43MzIwNTENCg0KIyB1c2Ugb3JkZXIgZGF0YSBzZXQNCiMgMDEuIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0KZGZfb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQoZGZfb3JkZXIsNSkNCiMgMDIuIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQp0Ymxfb3JkZXIgPC0gdGJsX2RmKGRmX29yZGVyKQ0KaGVhZCh0Ymxfb3JkZXIsIDUpDQoNCiMgMDMuIG11dGF0ZSB5ZWFyIGFuZCBtb250aCBjb2x1bW4NCm1fb3JkZXIgPC0gbXV0YXRlKHRibF9vcmRlciwNCiAgICAgICAgICAgICAgICAgIG95ZWFyID0gc3Vic3RyKG9yZGVyZGF0ZSwgMSwgNCksDQogICAgICAgICAgICAgICAgICBvbW9udGggPSBzdWJzdHIob3JkZXJkYXRlLCA2LCA3KSkNCmhlYWQobV9vcmRlciwgNSkNCg0KIyAwNC4gZ3JvdXAgYnkgbW9udGgNCm1fb3JkZXJfbW9udGggPC0gZ3JvdXBfYnkobV9vcmRlcixvbW9udGgpDQoNCiMgMDUuIHN1bW1hcmlzZSBvcmRlciBjb3VudCBieSBtb250aA0Kc3VtbWFyaXNlKG1fb3JkZXJfbW9udGgsIG1vbnRobHlfb3JkZXJfY291bnQgPSBuKCkpDQoNCg0KIyB1c2UgcGlwZSBmdW5jdGlvbiByZXdyaXRlIGFib3ZlIGZsb3cgMDMsMDQsMDUNCnRibF9vcmRlciAlPiUNCiAgbXV0YXRlKG95ZWFyID0gc3Vic3RyKG9yZGVyZGF0ZSwgMSwgNCksDQogICAgICAgICBvbW9udGggPSBzdWJzdHIob3JkZXJkYXRlLCA2LCA3KSkgJT4lDQogIGdyb3VwX2J5KG9tb250aCkgJT4lDQogIHN1bW1hcmlzZShtb250aGx5X29yZGVyX2NvdW50ID0gbigpKQ0KIyBBIHRpYmJsZTogMTIgw5cgMg0KIyAgICBvbW9udGggbW9udGhseV9vcmRlcl9jb3VudA0KIyAgICAgPGNocj4gICAgICAgICAgICAgICA8aW50Pg0KIyAxICAgICAgMDEgICAgICAgICAgICAgICAxMzYwMQ0KIyAyICAgICAgMDIgICAgICAgICAgICAgICAgNjYwOQ0KIyAzICAgICAgMDMgICAgICAgICAgICAgICAgNjIzNQ0KIyA0ICAgICAgMDQgICAgICAgICAgICAgICAgNjA0Mg0KIyA1ICAgICAgMDUgICAgICAgICAgICAgICAgNTAzNw0KIyA2ICAgICAgMDYgICAgICAgICAgICAgICAgNDY5MQ0KIyA3ICAgICAgMDcgICAgICAgICAgICAgICAgNDM1NA0KIyA4ICAgICAgMDggICAgICAgICAgICAgICAgNDc2Mw0KIyA5ICAgICAgMDkgICAgICAgICAgICAgICAgNTY3Ng0KIyAxMCAgICAgMTAgICAgICAgICAgICAgICAgNzEwNg0KIyAxMSAgICAgMTEgICAgICAgICAgICAgICAxNzI2OA0KIyAxMiAgICAgMTIgICAgICAgICAgICAgICAxODYxOA0KDQpgYGANCg0KIyMgQ2hhcHRlcjExIGNvbHdpc2Xlkoxkb+WHveaVsA0K562b6YCJ6ZSA5ZSu6aKd5q+P5bm05pyA5aSn55qE6K6w5b2VDQpgYGB7ciBjb2x3aXNlIGFuZCBkbyBmdW5jdGlvbn0NCiMgTG9hZCBkcGx5ciBwYWNrYWdlDQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQoNCiMgaW1wb3J0IGRhdGENCm9yZGVyIDwtIHJlYWQuY3N2KCJkcGx5ci1kYXRhL29yZGVyLmNzdiIpDQoNCiMgR2V0IFllYXJseSBPcmRlciBkYXRhIGFuZCBzcGxpdCBieSB5ZWFyDQpZZWFybHlfT3JkZXIgPC0gb3JkZXIgJT4lIHNlbGVjdChvcmRlcmRhdGUsIHRvdGFscHJpY2UpICU+JQ0KICAgICAgICAgICAgICAgICAgbXV0YXRlKG95ZWFyID0gc3Vic3RyKG9yZGVyZGF0ZSwgMSwgNCkpDQoNCiMgR3JvdXAgYnkgWWVhciwgR2V0IFllYWx5IE1heGltdW4gT3JkZXINClllYWx5X01heGltdW4gPC0gWWVhcmx5X09yZGVyICU+JSBncm91cF9ieShveWVhcikgJT4lDQogICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobWF4KHRvdGFscHJpY2UpKQ0KDQpgYGANCg0K562b6YCJ5q+P5bm06ZSA5ZSu6aKd5pyA5aSn55qE5Lik5p2h6K6w5b2VDQpgYGB7ciBkbyhkYXRhLCBmdW4oLikpfQ0KIyBMb2FkIGRwbHlyIHBhY2thZ2UNCmlmKCFzdXBwcmVzc1dhcm5pbmdzKHJlcXVpcmUoZHBseXIpKSkNCnsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCdkcGx5cicpDQogICAgcmVxdWlyZShkcGx5cikNCn0NCg0KIyBpbXBvcnQgZGF0YQ0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCg0KIyBHZXQgWWVhcmx5IE9yZGVyIGRhdGEgYW5kIHNwbGl0IGJ5IHllYXINClllYXJseV9PcmRlciA8LSBvcmRlciAlPiUgc2VsZWN0KG9yZGVyZGF0ZSwgdG90YWxwcmljZSkgJT4lDQogICAgICAgICAgICAgICAgICBtdXRhdGUob3llYXIgPSBzdWJzdHIob3JkZXJkYXRlLCAxLCA0KSkNCg0KIyBHcm91cCBieSBZZWFyLCBHZXQgWWVhbHkgTWF4IDIgT3JkZXJzDQpZZWFybHlfT3JkZXIgJT4lIGdyb3VwX2J5KG95ZWFyKSAlPiUNCiAgICAgICAgYXJyYW5nZShkZXNjKHRvdGFscHJpY2UpKSAlPiUNCiAgICAgICAgZG8oLiwgaGVhZCguLCAyKSkNCiMgU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFsxMiB4IDNdDQojIEdyb3Vwczogb3llYXIgWzZdDQojDQojICAgICBvcmRlcmRhdGUgdG90YWxwcmljZSBveWVhcg0KIyAgICAgICAgPGZjdHI+ICAgICAgPGRibD4gPGNocj4NCiMgMSAgMjAwOS0xMi0xNyAgICAyMjQ0LjAwICAyMDA5DQojIDIgIDIwMDktMTAtMjYgICAgMTE1NC42NSAgMjAwOQ0KIyAzICAyMDEwLTA5LTA1ICAgIDIyNTAuMDAgIDIwMTANCiMgNCAgMjAxMC0xMC0wNiAgICAyMjUwLjAwICAyMDEwDQojIDUgIDIwMTEtMDUtMDkgICAgMjI1MC4wMCAgMjAxMQ0KIyA2ICAyMDExLTA1LTE3ICAgIDIwMDAuMDAgIDIwMTENCiMgNyAgMjAxMi0xMi0xMiAgICA2NzgwLjAwICAyMDEyDQojIDggIDIwMTItMTEtMTIgICAgNjYwNi4wMCAgMjAxMg0KIyA5ICAyMDEzLTAxLTE4ICAgIDQwNTAuMDAgIDIwMTMNCiMgMTAgMjAxMy0wNi0yNiAgICAzNTkyLjAwICAyMDEzDQojIDExIDIwMTQtMDMtMjkgICAgNDczNS4wMCAgMjAxNA0KIyAxMiAyMDE0LTAzLTMwICAgIDQzNzguNTAgIDIwMTQNCg0KYGBgDQoNCiMjIyBwbHlyIHBhY2thZ2UgY29sd2lzZSBmdW5jdGlvbg0KYGBge3IgY29sd2lzZSBmdW5jdGlvbn0NCiMgTG9hZCBwbHlyIHBhY2thZ2UNCmlmKCFzdXBwcmVzc1dhcm5pbmdzKHJlcXVpcmUocGx5cikpKQ0Kew0KICAgIGluc3RhbGwucGFja2FnZXMoJ3BseXInKQ0KICAgIHJlcXVpcmUocGx5cikNCn0NCg0KIyBsb2FkIGFuZCBjaGVjayBpcmlzIGRhdGEgc2V0DQpoZWFkKGlyaXMsIDUpDQoNCiMgdG8gcm91bmQgZXZlcnkgY29sdW1uIHVzZSBjb2x3aXNlIGZ1bmN0aW9uDQojIGNhbGwgZnVuY3Rpb24gdG8gZWFjaCBjb2x1bW4NCiMgY29sd2lzZShmdW5jdGlvbikoZGF0YS5mcmFtZSkNCmNvbHdpc2Uocm91bmQpKGlyaXNbLCAxOjRdKSAlPiUgaGVhZCguLCA1KQ0KIyAgIFNlcGFsLkxlbmd0aCBTZXBhbC5XaWR0aCBQZXRhbC5MZW5ndGggUGV0YWwuV2lkdGgNCiMgMSAgICAgICAgICAgIDUgICAgICAgICAgIDQgICAgICAgICAgICAxICAgICAgICAgICAwDQojIDIgICAgICAgICAgICA1ICAgICAgICAgICAzICAgICAgICAgICAgMSAgICAgICAgICAgMA0KIyAzICAgICAgICAgICAgNSAgICAgICAgICAgMyAgICAgICAgICAgIDEgICAgICAgICAgIDANCiMgNCAgICAgICAgICAgIDUgICAgICAgICAgIDMgICAgICAgICAgICAyICAgICAgICAgICAwDQojIDUgICAgICAgICAgICA1ICAgICAgICAgICA0ICAgICAgICAgICAgMSAgICAgICAgICAgMA0KDQpgYGANCg0KIyMgQ2hhcHRlcjEyIOi/nuaOpU15U1FM5pWw5o2u5bqTDQrov57mjqVNeVNRTOaVsOaNruW6kw0KYGBge3IgY29ubmVjdCBteXNxbH0NCiMgbXlzcWwgZGF0YSBiYXNlDQpzcmNfZGF0YWJhc2UgPC0gc3JjX215c3FsKGRibmFtZSA9ICJzcWxib29rIiwgaG9zdCA9ICIxMjcuMC4wLjEiLCBwb3J0ID0gIjMwNjMiLHVzZXIgPSAicm9vdCIscGFzc3dvcmQgPSAicm9vdCIpDQoNCiMgbXlzcWwgdGFibGUNCnNyY190YWJsZSA8LSB0Ymwoc3JjX2RhdGFiYXNlLCBmcm9tID0gIm9yZGVycyIpDQoNCiMgZXhlY3V0ZSBzcWwgY29tbWFuZA0Kc3FsUXVlcnlSZXN1bHRzIDwtIHNlbGVjdChzcmNfdGFibGUsIG9yZGVyaWQsIG9yZGVyZGF0ZSkNCiMgb3IgdXNlIHBpcGUgZnVuY3Rpb24NCnNxbFF1ZXJ5UmVzdWx0cyA8LSBzcmNfdGFibGUgJT4lIHNlbGVjdChvcmRlcmlkLCBvcmRlcmRhdGUpDQoNCiMgY2hlY2sgc3FsIHF1ZXJ5IGNvbW1hbmQNCnNxbFF1ZXJ5UmVzdWx0cyRxdWVyeQ0KDQojIHNhdmUgcmVzdWx0cyBhcyBjc3YgZmlsZQ0Kd3JpdGUuY3N2KHNxbFF1ZXJ5UmVzdWx0cywgImRwbHlyLWRhdGEvb3JkZXJfcmVjb3JkLmNzdiIpDQoNCiMgc2hvdyBzcWxRdWVyeVJlc3VsdHMNCnNxbFF1ZXJ5UmVzdWx0cw0KDQojIG15c3FsIGRhdGEgYmFzZQ0KIyBteXNxbCAtdSByb290IC1wDQojIGVudGVyIHBhc3N3b3JkDQoNCiMgc2hvdyBkYXRhYmFzZXMNCiMgc2hvdyBkYXRhYmFzZXMNCg0KI3VzZSB3aGljaCBkYXRhYmFzZSwgY2hhbmdlIHRvIHlvdXIgZGF0YWJhc2UNCiMgdXNlIG15ZGF0YWJhc2UNCg0KIyBzaG93IHRhYmxlcyBpbiB5b3VyIGRhdGFiYXNlDQojIHNob3cgdGFibGVzDQoNCmBgYA0KDQojIyBDaGFwdGVyMTMgRXhhbXBsZSBkcGx5ciBhbmQgcGlwZWxpbmUgb3BlcmF0b3INCg0KPiBbZHBseXIgRXhhbXBsZXMgd2l0aCBwaXBlbGluZV0oaHR0cHM6Ly9yZW5rdW4ubWUvcGlwZVItdHV0b3JpYWwvRXhhbXBsZXMvZHBseXIuaHRtbCkNCg0KPiBbcmxpc3QgRXhhbXBsZXMgd2l0aCBwaXBlbGluZV0oaHR0cHM6Ly9yZW5rdW4ubWUvcGlwZVItdHV0b3JpYWwvRXhhbXBsZXMvcmxpc3QuaHRtbCkNCg0KDQpgaGZsaWdodHNgIGlzIGEgZGF0YXNldCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCBmbGlnaHRzIHRoYXQgZGVwYXJ0ZWQgSG91c3RvbiBpbiAyMDExLiBJbiB0aGUgZGVzY3JpcHRpb24gdGhlIGF1dGhvciB3cml0ZXM6DQoNCj4gVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGFsbCBmbGlnaHRzIGRlcGFydGluZyBmcm9tIEhvdXN0b24gYWlycG9ydHMgSUFIIChHZW9yZ2UgQnVzaCBJbnRlcmNvbnRpbmVudGFsKSBhbmQgSE9VIChIb3VzdG9uIEhvYmJ5KS4gVGhlIGRhdGEgY29tZXMgZnJvbSB0aGUgUmVzZWFyY2ggYW5kIElubm92YXRpb24gVGVjaG5vbG9neSBBZG1pbmlzdHJhdGlvbiBhdCB0aGUgQnVyZWF1IG9mIFRyYW5zcG9yYXRpb24gc3RhdGlzdGljczogW2h0dHA6Ly93d3cudHJhbnN0YXRzLmJ0cy5nb3YvRGF0YWJhc2VJbmZvLmFzcD9EQl9JRD0xMjAmTGluaz0wXShodHRwOi8vd3d3LnRyYW5zdGF0cy5idHMuZ292L0RhdGFiYXNlSW5mby5hc3A/REJfSUQ9MTIwJkxpbms9MCkNCg0KSGF2aW5nIGtub3duIHdoYXQgdGhlIGRhdGEgaXMgYWxsIGFib3V0LCB0aGVuIHdlIGxvYWQgdGhlIGxpYnJhcmllcyBhbmQgdGFrZSBhIGxvb2sgYXQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4NCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKGMoImRwbHlyIiwiaGZsaWdodHMiKSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBpcGVSKQ0KIyBvciB1c2UNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KGhmbGlnaHRzKSAjIGluc3RhbGwucGFja2FnZXMoImhmbGlnaHRzIikNCmRhdGEoaGZsaWdodHMpDQoNCnN0cihoZmxpZ2h0cykNCiMgJ2RhdGEuZnJhbWUnOgkyMjc0OTYgb2JzLiBvZiAgMjEgdmFyaWFibGVzOg0KIyAgJCBZZWFyICAgICAgICAgICAgIDogaW50ICAyMDExIDIwMTEgMjAxMSAyMDExIDIwMTEgMjAxMSAyMDExIDIwMTEgMjAxMSAyMDExIC4uLg0KIyAgJCBNb250aCAgICAgICAgICAgIDogaW50ICAxIDEgMSAxIDEgMSAxIDEgMSAxIC4uLg0KIyAgJCBEYXlvZk1vbnRoICAgICAgIDogaW50ICAxIDIgMyA0IDUgNiA3IDggOSAxMCAuLi4NCiMgICQgRGF5T2ZXZWVrICAgICAgICA6IGludCAgNiA3IDEgMiAzIDQgNSA2IDcgMSAuLi4NCiMgICQgRGVwVGltZSAgICAgICAgICA6IGludCAgMTQwMCAxNDAxIDEzNTIgMTQwMyAxNDA1IDEzNTkgMTM1OSAxMzU1IDE0NDMgMTQ0MyAuLi4NCiMgICQgQXJyVGltZSAgICAgICAgICA6IGludCAgMTUwMCAxNTAxIDE1MDIgMTUxMyAxNTA3IDE1MDMgMTUwOSAxNDU0IDE1NTQgMTU1MyAuLi4NCiMgICQgVW5pcXVlQ2FycmllciAgICA6IGNociAgIkFBIiAiQUEiICJBQSIgIkFBIiAuLi4NCiMgICQgRmxpZ2h0TnVtICAgICAgICA6IGludCAgNDI4IDQyOCA0MjggNDI4IDQyOCA0MjggNDI4IDQyOCA0MjggNDI4IC4uLg0KIyAgJCBUYWlsTnVtICAgICAgICAgIDogY2hyICAiTjU3NkFBIiAiTjU1N0FBIiAiTjU0MUFBIiAiTjQwM0FBIiAuLi4NCiMgICQgQWN0dWFsRWxhcHNlZFRpbWU6IGludCAgNjAgNjAgNzAgNzAgNjIgNjQgNzAgNTkgNzEgNzAgLi4uDQojICAkIEFpclRpbWUgICAgICAgICAgOiBpbnQgIDQwIDQ1IDQ4IDM5IDQ0IDQ1IDQzIDQwIDQxIDQ1IC4uLg0KIyAgJCBBcnJEZWxheSAgICAgICAgIDogaW50ICAtMTAgLTkgLTggMyAtMyAtNyAtMSAtMTYgNDQgNDMgLi4uDQojICAkIERlcERlbGF5ICAgICAgICAgOiBpbnQgIDAgMSAtOCAzIDUgLTEgLTEgLTUgNDMgNDMgLi4uDQojICAkIE9yaWdpbiAgICAgICAgICAgOiBjaHIgICJJQUgiICJJQUgiICJJQUgiICJJQUgiIC4uLg0KIyAgJCBEZXN0ICAgICAgICAgICAgIDogY2hyICAiREZXIiAiREZXIiAiREZXIiAiREZXIiAuLi4NCiMgICQgRGlzdGFuY2UgICAgICAgICA6IGludCAgMjI0IDIyNCAyMjQgMjI0IDIyNCAyMjQgMjI0IDIyNCAyMjQgMjI0IC4uLg0KIyAgJCBUYXhpSW4gICAgICAgICAgIDogaW50ICA3IDYgNSA5IDkgNiAxMiA3IDggNiAuLi4NCiMgICQgVGF4aU91dCAgICAgICAgICA6IGludCAgMTMgOSAxNyAyMiA5IDEzIDE1IDEyIDIyIDE5IC4uLg0KIyAgJCBDYW5jZWxsZWQgICAgICAgIDogaW50ICAwIDAgMCAwIDAgMCAwIDAgMCAwIC4uLg0KIyAgJCBDYW5jZWxsYXRpb25Db2RlIDogY2hyICAiIiAiIiAiIiAiIiAuLi4NCiMgICQgRGl2ZXJ0ZWQgICAgICAgICA6IGludCAgMCAwIDAgMCAwIDAgMCAwIDAgMCAuLi4NCmBgYA0KDQpUaGUgZGF0YSBpcyB0YWJ1bGFyIGFuZCB2ZXJ5IHdlbGwgZml0IGluIGEgZGF0YSBmcmFtZS4gUmVtYXJrYWJseSBpdCBoYXMgMjI3NDk2IHJvd3Mgd2hpY2ggaXMgbXVjaCBsYXJnZXIgdGhhbiBzbWFsbCBkYXRhc2V0cyBsaWtlIG10Y2Fycy4NCg0KVHdvIGNvbHVtbnMgaW4gdGhlIGRhdGEgZnJhbWUgYXR0cmFjdHMgb3VyIGF0dGVudGlvbjogYERpc3RhbmNlYCBhbmQgYEFjdHVhbEVsYXBzZWRUaW1lYC4gSWYgd2UgZGl2aWRlIERpc3RhbmNlIGJ5IEFjdHVhbEVsYXBzZWRUaW1lIHdlIGNhbiBnZXQgdGhlIGFjdHVhbCBmbGlnaHQgc3BlZWQuIFRoZXJlZm9yZSwgaW4gdGhpcyBleGFtcGxlLCB3ZSB1c2UgZHBseXIgZnVuY3Rpb25zIHRvIHRyYW5zZm9ybSB0aGUgZGF0YSBpbiBwaXBlbGluZSBhbmQgc2VlIHdoaWNoIGNhcnJpZXIgaGFzIGZhc3RlciBmbGlnaHRzLg0KDQpgYGB7cn0NCmhmbGlnaHRzICU+JSANCiAgIyAxLiBmaWx0ZXIgb3V0IG5vIGNhbmNlbGQgZmxpZ2h0DQogIGZpbHRlcihDYW5jZWxsZWQgPT0gMCkgJT4lDQogICMgMi4gbXV0YXRlIG5ldyBjb2x1bW4gc3BlZWQNCiAgbXV0YXRlKHNwZWVkID0gRGlzdGFuY2UgLyBBY3R1YWxFbGFwc2VkVGltZSkgJT4lDQogICMgMy4gc2F2ZSB0byBoZmxpZ2h0czINCiAgKH4gaGZsaWdodHMyKSAlPiUgDQogICMgNC4gZ3JvdXBfYnkgVW5pcXVlQ2Fycmllcg0KICAgIGdyb3VwX2J5KFVuaXF1ZUNhcnJpZXIpICU+JQ0KICAgICNncm91cF9ieSguZGF0YSA9IC4sVW5pcXVlQ2FycmllcikgICU+JQ0KICAjIDUuIHN1bW1hcml6ZQ0KICBzdW1tYXJpemUobWVhbl9zcGVlZCA9IG1lYW4oc3BlZWQsbmEucm0gPSBUUlVFKSkgJT4lDQogICMgNi4gYXJyYW5nZSwgYnkgc3BlZWQgZGVzYw0KICBhcnJhbmdlKGRlc2MobWVhbl9zcGVlZCkpICU+JQ0KICAjIDcuIGJhcnBsb3QsIHdoeSB3aXRoPw0KICB3aXRoKGJhcnBsb3QobWVhbl9zcGVlZCxuYW1lcy5hcmcgPSBVbmlxdWVDYXJyaWVyLA0KICAgIG1haW4gPSAiQXZlcmFnZSBmbGlnaHQgc3BlZWQiKSkNCmBgYA0KDQoNCg0KDQojIyBFbmQgMjAxNy0wNi0xMCBCeSBTdG9uZS5Ib3UNCg0KVXBkYXRlZCBpbiAyMDE3MDcwMiwgYWRkIGV4YW1wbGUNCg==